Files
neo/FIELD_TYPES_GUIDE.md

11 KiB

Field Types & Views System

A comprehensive field type system inspired by Laravel Nova, built with Vue 3 and shadcn-vue components. This system provides a flexible way to define and render fields in list, detail, and edit views.

Overview

The system consists of:

  1. Field Type Definitions - TypeScript types and enums defining all available field types
  2. Field Renderer - A universal component that renders fields based on type and view mode
  3. View Components - ListView (data table), DetailView, and EditView components
  4. Composables - Utilities for working with fields and managing CRUD operations
  5. Backend Support - Extended field definitions with UI metadata

Field Types

Text Fields

  • TEXT - Single-line text input
  • TEXTAREA - Multi-line text input
  • PASSWORD - Password input (masked)
  • EMAIL - Email input with validation
  • URL - URL input

Numeric Fields

  • NUMBER - Numeric input
  • CURRENCY - Currency input with formatting

Selection Fields

  • SELECT - Dropdown select
  • MULTI_SELECT - Multi-select dropdown
  • BOOLEAN - Checkbox/switch

Date/Time Fields

  • DATE - Date picker
  • DATETIME - Date and time picker
  • TIME - Time picker

Relationship Fields

  • BELONGS_TO - Many-to-one relationship
  • HAS_MANY - One-to-many relationship
  • MANY_TO_MANY - Many-to-many relationship

Rich Content

  • MARKDOWN - Markdown editor
  • CODE - Code editor

File Fields

  • FILE - File upload
  • IMAGE - Image upload

Other

  • COLOR - Color picker
  • JSON - JSON editor

Usage

Basic Example

<script setup lang="ts">
import { ListView, DetailView, EditView } from '@/components/views'
import { FieldType, ViewMode } from '@/types/field-types'

// Define your fields
const fields = [
  {
    id: '1',
    apiName: 'name',
    label: 'Name',
    type: FieldType.TEXT,
    isRequired: true,
    placeholder: 'Enter name',
    showOnList: true,
    showOnDetail: true,
    showOnEdit: true,
  },
  {
    id: '2',
    apiName: 'email',
    label: 'Email',
    type: FieldType.EMAIL,
    isRequired: true,
    validationRules: [
      { type: 'email', message: 'Invalid email format' }
    ],
  },
  {
    id: '3',
    apiName: 'status',
    label: 'Status',
    type: FieldType.SELECT,
    options: [
      { label: 'Active', value: 'active' },
      { label: 'Inactive', value: 'inactive' },
    ],
  },
]

// Create view config
const listConfig = {
  objectApiName: 'Contact',
  mode: ViewMode.LIST,
  fields,
  searchable: true,
  exportable: true,
}

const data = ref([])
</script>

<template>
  <ListView 
    :config="listConfig" 
    :data="data"
    selectable
    @row-click="handleRowClick"
    @create="handleCreate"
  />
</template>

Using with Backend Data

<script setup lang="ts">
import { useFields, useViewState } from '@/composables/useFieldViews'
import { ListView } from '@/components/views'

const { buildListViewConfig } = useFields()
const { 
  records, 
  loading, 
  fetchRecords,
  showDetail,
  showEdit,
  deleteRecords 
} = useViewState('/api/contacts')

// Fetch object definition from backend
const objectDef = await $fetch('/api/objects/contact')

// Build view config from backend data
const listConfig = buildListViewConfig(objectDef, {
  searchable: true,
  exportable: true,
})

// Fetch records
await fetchRecords()
</script>

<template>
  <ListView
    :config="listConfig"
    :data="records"
    :loading="loading"
    @row-click="showDetail"
    @create="showEdit"
    @delete="deleteRecords"
  />
</template>

Sections and Grouping

const detailConfig = {
  objectApiName: 'Contact',
  mode: ViewMode.DETAIL,
  fields,
  sections: [
    {
      title: 'Basic Information',
      description: 'Primary contact details',
      fields: ['firstName', 'lastName', 'email'],
    },
    {
      title: 'Company Information',
      fields: ['company', 'jobTitle', 'department'],
    },
    {
      title: 'Additional Details',
      fields: ['notes', 'tags'],
      collapsible: true,
      defaultCollapsed: true,
    },
  ],
}

Field Configuration

FieldConfig Interface

interface FieldConfig {
  // Basic properties
  id: string
  apiName: string
  label: string
  type: FieldType
  
  // Display
  placeholder?: string
  helpText?: string
  defaultValue?: any
  
  // Validation
  isRequired?: boolean
  isReadOnly?: boolean
  validationRules?: FieldValidationRule[]
  
  // View visibility
  showOnList?: boolean
  showOnDetail?: boolean
  showOnEdit?: boolean
  sortable?: boolean
  
  // Type-specific options
  options?: FieldOption[]      // For select fields
  rows?: number                // For textarea
  min?: number                 // For number/date
  max?: number                 // For number/date
  step?: number                // For number
  accept?: string              // For file uploads
  relationObject?: string      // For relationships
  
  // Formatting
  format?: string
  prefix?: string
  suffix?: string
}

Validation Rules

const field = {
  // ... other config
  validationRules: [
    { type: 'required', message: 'This field is required' },
    { type: 'min', value: 5, message: 'Minimum 5 characters' },
    { type: 'max', value: 100, message: 'Maximum 100 characters' },
    { type: 'email', message: 'Invalid email format' },
    { type: 'url', message: 'Invalid URL format' },
    { type: 'pattern', value: '^[A-Z]', message: 'Must start with uppercase' },
  ],
}

View Components

ListView

Features:

  • Data table with sortable columns
  • Row selection with bulk actions
  • Search functionality
  • Custom actions
  • Export capability
  • Pagination support

Events:

  • row-click - When a row is clicked
  • row-select - When rows are selected
  • create - When create button is clicked
  • edit - When edit button is clicked
  • delete - When delete is triggered
  • action - When custom action is triggered
  • sort - When column sort changes
  • search - When search is performed

DetailView

Features:

  • Organized sections
  • Collapsible sections
  • Custom actions
  • Read-only display optimized for each field type

Events:

  • edit - When edit button is clicked
  • delete - When delete button is clicked
  • back - When back button is clicked
  • action - When custom action is triggered

EditView

Features:

  • Form with validation
  • Organized sections with collapsible support
  • Required field indicators
  • Help text and placeholders
  • Error messages
  • Save/Cancel actions

Events:

  • save - When form is submitted (passes validated data)
  • cancel - When cancel is clicked
  • back - When back is clicked

Backend Integration

Field Definition Model

export interface UIMetadata {
  placeholder?: string
  helpText?: string
  showOnList?: boolean
  showOnDetail?: boolean
  showOnEdit?: boolean
  sortable?: boolean
  options?: FieldOption[]
  rows?: number
  min?: number
  max?: number
  step?: number
  format?: string
  prefix?: string
  suffix?: string
  validationRules?: ValidationRule[]
}

export class FieldDefinition extends BaseModel {
  // ... existing fields
  uiMetadata?: UIMetadata
}

Migration

Run the migration to add UI metadata support:

cd backend
npm run migrate:tenant

API Response Example

{
  "id": "field-1",
  "objectDefinitionId": "obj-1",
  "apiName": "firstName",
  "label": "First Name",
  "type": "text",
  "isRequired": true,
  "uiMetadata": {
    "placeholder": "Enter first name",
    "helpText": "Customer's legal first name",
    "showOnList": true,
    "showOnDetail": true,
    "showOnEdit": true,
    "sortable": true,
    "validationRules": [
      {
        "type": "min",
        "value": 2,
        "message": "Name must be at least 2 characters"
      }
    ]
  }
}

Composables

useFields()

Utilities for working with field configurations:

  • mapFieldDefinitionToConfig(fieldDef) - Convert backend field definition to FieldConfig
  • buildListViewConfig(objectDef, customConfig) - Build ListView configuration
  • buildDetailViewConfig(objectDef, customConfig) - Build DetailView configuration
  • buildEditViewConfig(objectDef, customConfig) - Build EditView configuration
  • generateSections(fields) - Auto-generate sections based on field types

useViewState(apiEndpoint)

CRUD operations and state management:

  • State: records, currentRecord, currentView, loading, saving, error
  • Methods: fetchRecords(), fetchRecord(id), createRecord(data), updateRecord(id, data), deleteRecord(id), deleteRecords(ids)
  • Navigation: showList(), showDetail(record), showEdit(record), handleSave(data)

Demo

Visit /demo/field-views to see an interactive demo of all field types and views.

Best Practices

  1. Field Organization - Group related fields into sections for better UX
  2. Validation - Always provide clear validation messages
  3. Help Text - Use help text to guide users
  4. Required Fields - Mark required fields appropriately
  5. Default Values - Provide sensible defaults when possible
  6. Read-Only Fields - Use for system fields or computed values
  7. Conditional Logic - Use dependsOn for conditional field visibility
  8. Mobile Responsive - All components are mobile-responsive by default

Extending

Adding Custom Field Types

  1. Add new type to FieldType enum in types/field-types.ts
  2. Add rendering logic to FieldRenderer.vue
  3. Update validation logic in EditView.vue

Custom Actions

const config = {
  // ... other config
  actions: [
    {
      id: 'export-pdf',
      label: 'Export PDF',
      icon: 'FileDown',
      variant: 'outline',
      confirmation: 'Export this record to PDF?',
      handler: async () => {
        // Custom logic
      }
    }
  ]
}

Components Structure

frontend/
├── components/
│   ├── fields/
│   │   └── FieldRenderer.vue      # Universal field renderer
│   ├── views/
│   │   ├── ListView.vue           # Data table view
│   │   ├── DetailView.vue         # Read-only detail view
│   │   └── EditView.vue           # Form/edit view
│   └── ui/                        # shadcn-vue components
│       ├── table/
│       ├── input/
│       ├── select/
│       ├── checkbox/
│       ├── switch/
│       ├── textarea/
│       ├── calendar/
│       ├── date-picker/
│       └── ...
├── types/
│   └── field-types.ts             # Type definitions
├── composables/
│   └── useFieldViews.ts           # Utilities
└── pages/
    └── demo/
        └── field-views.vue        # Interactive demo

Performance Considerations

  • Fields are rendered on-demand based on view mode
  • Large datasets should use pagination (built-in support)
  • Validation is performed client-side before API calls
  • Use v-memo for large lists to optimize re-renders

Accessibility

All components follow accessibility best practices:

  • Proper ARIA labels
  • Keyboard navigation support
  • Focus management
  • Screen reader friendly
  • High contrast support

License

Part of the Neo platform.