Added auth functionality, initial work with views and field types
This commit is contained in:
479
FIELD_TYPES_GUIDE.md
Normal file
479
FIELD_TYPES_GUIDE.md
Normal file
@@ -0,0 +1,479 @@
|
||||
# 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
|
||||
|
||||
```vue
|
||||
<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
|
||||
|
||||
```vue
|
||||
<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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
npm run migrate:tenant
|
||||
```
|
||||
|
||||
### API Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"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](../types/field-types.ts)
|
||||
2. Add rendering logic to [FieldRenderer.vue](../components/fields/FieldRenderer.vue)
|
||||
3. Update validation logic in [EditView.vue](../components/views/EditView.vue)
|
||||
|
||||
### Custom Actions
|
||||
|
||||
```typescript
|
||||
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.
|
||||
Reference in New Issue
Block a user