mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-05-05 19:19:35 +00:00
Merge pull request #262 from johndoe6345789/codex/add-schema/default/forms,-components-and-validation
Refactor default schema into modular files
This commit is contained in:
@@ -1,308 +1,6 @@
|
||||
import type { SchemaConfig } from '../types/schema-types'
|
||||
import { defaultApps } from './default/components'
|
||||
|
||||
export const defaultSchema: SchemaConfig = {
|
||||
apps: [
|
||||
{
|
||||
name: 'blog',
|
||||
label: 'Blog',
|
||||
models: [
|
||||
{
|
||||
name: 'post',
|
||||
label: 'Post',
|
||||
labelPlural: 'Posts',
|
||||
icon: 'Article',
|
||||
listDisplay: ['title', 'author', 'status', 'publishedAt'],
|
||||
listFilter: ['status', 'author'],
|
||||
searchFields: ['title', 'content'],
|
||||
ordering: ['-publishedAt'],
|
||||
fields: [
|
||||
{
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
label: 'ID',
|
||||
required: true,
|
||||
unique: true,
|
||||
editable: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
label: 'Title',
|
||||
required: true,
|
||||
validation: {
|
||||
minLength: 3,
|
||||
maxLength: 200,
|
||||
},
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'string',
|
||||
label: 'Slug',
|
||||
required: true,
|
||||
unique: true,
|
||||
helpText: 'URL-friendly version of the title',
|
||||
validation: {
|
||||
pattern: '^[a-z0-9-]+$',
|
||||
},
|
||||
listDisplay: false,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'text',
|
||||
label: 'Content',
|
||||
required: true,
|
||||
helpText: 'Main post content',
|
||||
listDisplay: false,
|
||||
searchable: true,
|
||||
},
|
||||
{
|
||||
name: 'excerpt',
|
||||
type: 'text',
|
||||
label: 'Excerpt',
|
||||
required: false,
|
||||
helpText: ['Short summary of the post', 'Used in list views and previews'],
|
||||
validation: {
|
||||
maxLength: 500,
|
||||
},
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
type: 'relation',
|
||||
label: 'Author',
|
||||
required: true,
|
||||
relatedModel: 'author',
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
type: 'select',
|
||||
label: 'Status',
|
||||
required: true,
|
||||
default: 'draft',
|
||||
choices: [
|
||||
{ value: 'draft', label: 'Draft' },
|
||||
{ value: 'published', label: 'Published' },
|
||||
{ value: 'archived', label: 'Archived' },
|
||||
],
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'featured',
|
||||
type: 'boolean',
|
||||
label: 'Featured',
|
||||
default: false,
|
||||
helpText: 'Display on homepage',
|
||||
listDisplay: true,
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
type: 'datetime',
|
||||
label: 'Published At',
|
||||
required: false,
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'tags',
|
||||
type: 'json',
|
||||
label: 'Tags',
|
||||
required: false,
|
||||
helpText: 'JSON array of tag strings',
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'views',
|
||||
type: 'number',
|
||||
label: 'Views',
|
||||
default: 0,
|
||||
validation: {
|
||||
min: 0,
|
||||
},
|
||||
listDisplay: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
label: 'Author',
|
||||
labelPlural: 'Authors',
|
||||
icon: 'User',
|
||||
listDisplay: ['name', 'email', 'active', 'createdAt'],
|
||||
listFilter: ['active'],
|
||||
searchFields: ['name', 'email'],
|
||||
ordering: ['name'],
|
||||
fields: [
|
||||
{
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
label: 'ID',
|
||||
required: true,
|
||||
unique: true,
|
||||
editable: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
label: 'Name',
|
||||
required: true,
|
||||
validation: {
|
||||
minLength: 2,
|
||||
maxLength: 100,
|
||||
},
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
label: 'Email',
|
||||
required: true,
|
||||
unique: true,
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
type: 'text',
|
||||
label: 'Bio',
|
||||
required: false,
|
||||
helpText: 'Author biography',
|
||||
validation: {
|
||||
maxLength: 1000,
|
||||
},
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
type: 'url',
|
||||
label: 'Website',
|
||||
required: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'active',
|
||||
type: 'boolean',
|
||||
label: 'Active',
|
||||
default: true,
|
||||
listDisplay: true,
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
type: 'datetime',
|
||||
label: 'Created At',
|
||||
required: true,
|
||||
editable: false,
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'ecommerce',
|
||||
label: 'E-Commerce',
|
||||
models: [
|
||||
{
|
||||
name: 'product',
|
||||
label: 'Product',
|
||||
labelPlural: 'Products',
|
||||
icon: 'ShoppingCart',
|
||||
listDisplay: ['name', 'price', 'stock', 'available'],
|
||||
listFilter: ['available', 'category'],
|
||||
searchFields: ['name', 'description'],
|
||||
ordering: ['name'],
|
||||
fields: [
|
||||
{
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
label: 'ID',
|
||||
required: true,
|
||||
unique: true,
|
||||
editable: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
label: 'Product Name',
|
||||
required: true,
|
||||
validation: {
|
||||
minLength: 3,
|
||||
maxLength: 200,
|
||||
},
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
label: 'Description',
|
||||
required: false,
|
||||
helpText: 'Product description',
|
||||
listDisplay: false,
|
||||
searchable: true,
|
||||
},
|
||||
{
|
||||
name: 'price',
|
||||
type: 'number',
|
||||
label: 'Price',
|
||||
required: true,
|
||||
validation: {
|
||||
min: 0,
|
||||
},
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'stock',
|
||||
type: 'number',
|
||||
label: 'Stock',
|
||||
required: true,
|
||||
default: 0,
|
||||
validation: {
|
||||
min: 0,
|
||||
},
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'category',
|
||||
type: 'select',
|
||||
label: 'Category',
|
||||
required: true,
|
||||
choices: [
|
||||
{ value: 'electronics', label: 'Electronics' },
|
||||
{ value: 'clothing', label: 'Clothing' },
|
||||
{ value: 'books', label: 'Books' },
|
||||
{ value: 'home', label: 'Home & Garden' },
|
||||
{ value: 'toys', label: 'Toys' },
|
||||
],
|
||||
listDisplay: false,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'available',
|
||||
type: 'boolean',
|
||||
label: 'Available',
|
||||
default: true,
|
||||
listDisplay: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
apps: defaultApps,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import type { AppSchema, ModelSchema } from '../../types/schema-types'
|
||||
import { authorFields, postFields, productFields } from './forms'
|
||||
|
||||
export const blogModels: ModelSchema[] = [
|
||||
{
|
||||
name: 'post',
|
||||
label: 'Post',
|
||||
labelPlural: 'Posts',
|
||||
icon: 'Article',
|
||||
listDisplay: ['title', 'author', 'status', 'publishedAt'],
|
||||
listFilter: ['status', 'author'],
|
||||
searchFields: ['title', 'content'],
|
||||
ordering: ['-publishedAt'],
|
||||
fields: postFields,
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
label: 'Author',
|
||||
labelPlural: 'Authors',
|
||||
icon: 'User',
|
||||
listDisplay: ['name', 'email', 'active', 'createdAt'],
|
||||
listFilter: ['active'],
|
||||
searchFields: ['name', 'email'],
|
||||
ordering: ['name'],
|
||||
fields: authorFields,
|
||||
},
|
||||
]
|
||||
|
||||
export const ecommerceModels: ModelSchema[] = [
|
||||
{
|
||||
name: 'product',
|
||||
label: 'Product',
|
||||
labelPlural: 'Products',
|
||||
icon: 'ShoppingCart',
|
||||
listDisplay: ['name', 'price', 'stock', 'available'],
|
||||
listFilter: ['available', 'category'],
|
||||
searchFields: ['name', 'description'],
|
||||
ordering: ['name'],
|
||||
fields: productFields,
|
||||
},
|
||||
]
|
||||
|
||||
export const defaultApps: AppSchema[] = [
|
||||
{
|
||||
name: 'blog',
|
||||
label: 'Blog',
|
||||
models: blogModels,
|
||||
},
|
||||
{
|
||||
name: 'ecommerce',
|
||||
label: 'E-Commerce',
|
||||
models: ecommerceModels,
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,244 @@
|
||||
import type { FieldSchema } from '../../types/schema-types'
|
||||
import { authorValidations, postValidations, productValidations } from './validation'
|
||||
|
||||
export const postFields: FieldSchema[] = [
|
||||
{
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
label: 'ID',
|
||||
required: true,
|
||||
unique: true,
|
||||
editable: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
label: 'Title',
|
||||
required: true,
|
||||
validation: postValidations.title,
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'string',
|
||||
label: 'Slug',
|
||||
required: true,
|
||||
unique: true,
|
||||
helpText: 'URL-friendly version of the title',
|
||||
validation: postValidations.slug,
|
||||
listDisplay: false,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'text',
|
||||
label: 'Content',
|
||||
required: true,
|
||||
helpText: 'Main post content',
|
||||
listDisplay: false,
|
||||
searchable: true,
|
||||
},
|
||||
{
|
||||
name: 'excerpt',
|
||||
type: 'text',
|
||||
label: 'Excerpt',
|
||||
required: false,
|
||||
helpText: ['Short summary of the post', 'Used in list views and previews'],
|
||||
validation: postValidations.excerpt,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
type: 'relation',
|
||||
label: 'Author',
|
||||
required: true,
|
||||
relatedModel: 'author',
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
type: 'select',
|
||||
label: 'Status',
|
||||
required: true,
|
||||
default: 'draft',
|
||||
choices: [
|
||||
{ value: 'draft', label: 'Draft' },
|
||||
{ value: 'published', label: 'Published' },
|
||||
{ value: 'archived', label: 'Archived' },
|
||||
],
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'featured',
|
||||
type: 'boolean',
|
||||
label: 'Featured',
|
||||
default: false,
|
||||
helpText: 'Display on homepage',
|
||||
listDisplay: true,
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
type: 'datetime',
|
||||
label: 'Published At',
|
||||
required: false,
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'tags',
|
||||
type: 'json',
|
||||
label: 'Tags',
|
||||
required: false,
|
||||
helpText: 'JSON array of tag strings',
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'views',
|
||||
type: 'number',
|
||||
label: 'Views',
|
||||
default: 0,
|
||||
validation: postValidations.views,
|
||||
listDisplay: false,
|
||||
},
|
||||
]
|
||||
|
||||
export const authorFields: FieldSchema[] = [
|
||||
{
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
label: 'ID',
|
||||
required: true,
|
||||
unique: true,
|
||||
editable: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
label: 'Name',
|
||||
required: true,
|
||||
validation: authorValidations.name,
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
label: 'Email',
|
||||
required: true,
|
||||
unique: true,
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
type: 'text',
|
||||
label: 'Bio',
|
||||
required: false,
|
||||
helpText: 'Author biography',
|
||||
validation: authorValidations.bio,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
type: 'url',
|
||||
label: 'Website',
|
||||
required: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'active',
|
||||
type: 'boolean',
|
||||
label: 'Active',
|
||||
default: true,
|
||||
listDisplay: true,
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
type: 'datetime',
|
||||
label: 'Created At',
|
||||
required: true,
|
||||
editable: false,
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
]
|
||||
|
||||
export const productFields: FieldSchema[] = [
|
||||
{
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
label: 'ID',
|
||||
required: true,
|
||||
unique: true,
|
||||
editable: false,
|
||||
listDisplay: false,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
label: 'Product Name',
|
||||
required: true,
|
||||
validation: productValidations.name,
|
||||
listDisplay: true,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
label: 'Description',
|
||||
required: false,
|
||||
helpText: 'Product description',
|
||||
listDisplay: false,
|
||||
searchable: true,
|
||||
},
|
||||
{
|
||||
name: 'price',
|
||||
type: 'number',
|
||||
label: 'Price',
|
||||
required: true,
|
||||
validation: productValidations.price,
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'stock',
|
||||
type: 'number',
|
||||
label: 'Stock',
|
||||
required: true,
|
||||
default: 0,
|
||||
validation: productValidations.stock,
|
||||
listDisplay: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'category',
|
||||
type: 'select',
|
||||
label: 'Category',
|
||||
required: true,
|
||||
choices: [
|
||||
{ value: 'electronics', label: 'Electronics' },
|
||||
{ value: 'clothing', label: 'Clothing' },
|
||||
{ value: 'books', label: 'Books' },
|
||||
{ value: 'home', label: 'Home & Garden' },
|
||||
{ value: 'toys', label: 'Toys' },
|
||||
],
|
||||
listDisplay: false,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'available',
|
||||
type: 'boolean',
|
||||
label: 'Available',
|
||||
default: true,
|
||||
listDisplay: true,
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { FieldSchema } from '../../types/schema-types'
|
||||
|
||||
export const postValidations: Record<string, FieldSchema['validation']> = {
|
||||
title: { minLength: 3, maxLength: 200 },
|
||||
slug: { pattern: '^[a-z0-9-]+$' },
|
||||
excerpt: { maxLength: 500 },
|
||||
views: { min: 0 },
|
||||
}
|
||||
|
||||
export const authorValidations: Record<string, FieldSchema['validation']> = {
|
||||
name: { minLength: 2, maxLength: 100 },
|
||||
bio: { maxLength: 1000 },
|
||||
}
|
||||
|
||||
export const productValidations: Record<string, FieldSchema['validation']> = {
|
||||
name: { minLength: 3, maxLength: 200 },
|
||||
price: { min: 0 },
|
||||
stock: { min: 0 },
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
// Schema utilities exports
|
||||
export * from './schema-utils'
|
||||
export { defaultSchema } from './default-schema'
|
||||
export * from './default/components'
|
||||
export * from './default/forms'
|
||||
export * from './default/validation'
|
||||
|
||||
Reference in New Issue
Block a user