formue-crud 0.1.77 → 0.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +772 -23
- package/dist/formue-crud.js +2318 -2323
- package/dist/formue-crud.umd.cjs +23 -20
- package/package.json +1 -1
package/README.md
CHANGED
@@ -1,46 +1,795 @@
|
|
1
|
-
#
|
1
|
+
# Formue CRUD - Complete Documentation
|
2
2
|
|
3
|
-
|
3
|
+
## Table of Contents
|
4
4
|
|
5
|
-
|
5
|
+
1. [Overview](#overview)
|
6
|
+
2. [Installation & Setup](#installation--setup)
|
7
|
+
3. [Core Components](#core-components)
|
8
|
+
4. [Architecture](#architecture)
|
9
|
+
5. [API Reference](#api-reference)
|
10
|
+
6. [Usage Examples](#usage-examples)
|
11
|
+
7. [Advanced Features](#advanced-features)
|
12
|
+
8. [Customization](#customization)
|
13
|
+
9. [Best Practices](#best-practices)
|
14
|
+
10. [Troubleshooting](#troubleshooting)
|
6
15
|
|
7
|
-
|
16
|
+
## Overview
|
8
17
|
|
9
|
-
|
18
|
+
Formue CRUD is a comprehensive Vue.js 3 framework designed for building data-driven applications with advanced CRUD operations. It provides a complete solution for managing data tables, forms, filtering, sorting, pagination, and user permissions.
|
10
19
|
|
11
|
-
|
20
|
+
### Key Features
|
12
21
|
|
13
|
-
|
22
|
+
- **Dynamic Data Tables**: Tabulator.js integration with advanced sorting and filtering
|
23
|
+
- **Form Management**: Vueform integration for dynamic form generation
|
24
|
+
- **Permission System**: Role-based access control for CRUD operations
|
25
|
+
- **Advanced Filtering**: Multi-field filtering with save/load functionality
|
26
|
+
- **Export Capabilities**: Excel export with customizable data
|
27
|
+
- **Responsive Design**: Mobile-friendly interface with Tailwind CSS
|
28
|
+
- **State Management**: Pinia-based reactive state management
|
29
|
+
- **Real-time Updates**: Event-driven architecture for live data updates
|
14
30
|
|
15
|
-
|
16
|
-
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
17
|
-
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
18
|
-
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
31
|
+
### Dependencies
|
19
32
|
|
20
|
-
|
33
|
+
```json
|
34
|
+
{
|
35
|
+
"@vueform/vueform": "^1.5.3",
|
36
|
+
"@vueuse/core": "^10.4.0",
|
37
|
+
"axios": "^1.6.2",
|
38
|
+
"lodash": "^4.17.21",
|
39
|
+
"mitt": "^3.0.1",
|
40
|
+
"pinia": "^2.1.6",
|
41
|
+
"qs": "^6.11.2",
|
42
|
+
"tabulator-tables": "^6.2.1",
|
43
|
+
"vue": "^3.3.4"
|
44
|
+
}
|
45
|
+
```
|
21
46
|
|
22
|
-
|
47
|
+
## Installation & Setup
|
23
48
|
|
24
|
-
|
49
|
+
### 1. Install the Package
|
25
50
|
|
26
|
-
```
|
27
|
-
npm install
|
51
|
+
```bash
|
52
|
+
npm install formue-crud
|
53
|
+
```
|
54
|
+
|
55
|
+
### 2. Import and Configure
|
56
|
+
|
57
|
+
```javascript
|
58
|
+
import { createApp } from 'vue'
|
59
|
+
import { createPinia } from 'pinia'
|
60
|
+
import FormueCrud from 'formue-crud'
|
61
|
+
|
62
|
+
const app = createApp(App)
|
63
|
+
app.use(createPinia())
|
64
|
+
app.use(FormueCrud)
|
65
|
+
```
|
66
|
+
|
67
|
+
### 3. Basic Setup
|
68
|
+
|
69
|
+
```vue
|
70
|
+
<template>
|
71
|
+
<MCrud
|
72
|
+
:fields="fields"
|
73
|
+
:options="options"
|
74
|
+
:route="route"
|
75
|
+
:hidden-actions="hiddenActions"
|
76
|
+
@mounted="onMounted"
|
77
|
+
/>
|
78
|
+
</template>
|
79
|
+
|
80
|
+
<script setup>
|
81
|
+
import { MCrud } from 'formue-crud'
|
82
|
+
|
83
|
+
const fields = {
|
84
|
+
name: {
|
85
|
+
type: 'text',
|
86
|
+
title: 'Name',
|
87
|
+
placeholder: 'Enter name'
|
88
|
+
},
|
89
|
+
email: {
|
90
|
+
type: 'email',
|
91
|
+
title: 'Email',
|
92
|
+
placeholder: 'Enter email'
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
const options = {
|
97
|
+
formMode: 'dialog' // or 'tab'
|
98
|
+
}
|
99
|
+
|
100
|
+
const route = {
|
101
|
+
index: '/api/users',
|
102
|
+
create: '/api/users',
|
103
|
+
update: '/api/users',
|
104
|
+
delete: '/api/users'
|
105
|
+
}
|
106
|
+
|
107
|
+
const hiddenActions = [] // ['create', 'update', 'delete', 'show']
|
108
|
+
</script>
|
109
|
+
```
|
110
|
+
|
111
|
+
## Core Components
|
112
|
+
|
113
|
+
### MCrud (Main Component)
|
114
|
+
|
115
|
+
The primary component that orchestrates all CRUD operations.
|
116
|
+
|
117
|
+
**Props:**
|
118
|
+
|
119
|
+
- `fields`: Object defining form fields and table columns
|
120
|
+
- `options`: Configuration object for behavior customization
|
121
|
+
- `structure`: Additional form structure configuration
|
122
|
+
- `hiddenActions`: Array of actions to hide from UI
|
123
|
+
- `tableOptions`: Tabulator-specific options
|
124
|
+
- `route`: API endpoints configuration
|
125
|
+
- `dir`: Text direction ('ltr' or 'rtl')
|
126
|
+
|
127
|
+
**Events:**
|
128
|
+
|
129
|
+
- `mounted`: Emitted when component is fully initialized
|
130
|
+
|
131
|
+
### MTable
|
132
|
+
|
133
|
+
Advanced data table component with sorting, filtering, and pagination.
|
134
|
+
|
135
|
+
**Features:**
|
136
|
+
|
137
|
+
- Column sorting with visual indicators
|
138
|
+
- Row selection with batch operations
|
139
|
+
- Custom column visibility
|
140
|
+
- Loading states and empty data handling
|
141
|
+
- Responsive design
|
142
|
+
|
143
|
+
### MFilter
|
144
|
+
|
145
|
+
Dynamic filtering system with save/load functionality.
|
146
|
+
|
147
|
+
**Features:**
|
148
|
+
|
149
|
+
- Field-specific filter types (text, date, select)
|
150
|
+
- Multiple filter combinations
|
151
|
+
- Save/load filter presets
|
152
|
+
- Real-time filter application
|
153
|
+
|
154
|
+
### FormCore
|
155
|
+
|
156
|
+
Dynamic form generation component using Vueform.
|
157
|
+
|
158
|
+
**Features:**
|
159
|
+
|
160
|
+
- Auto-generated forms from field definitions
|
161
|
+
- Validation integration
|
162
|
+
- Conditional field display
|
163
|
+
- Multi-step form support
|
164
|
+
|
165
|
+
### MButtonBox
|
166
|
+
|
167
|
+
Action toolbar with permissions-based button visibility.
|
168
|
+
|
169
|
+
**Features:**
|
170
|
+
|
171
|
+
- Create, export, reload, column selection buttons
|
172
|
+
- Permission-based visibility
|
173
|
+
- Batch operation support
|
174
|
+
- Search integration
|
175
|
+
|
176
|
+
## Architecture
|
177
|
+
|
178
|
+
### State Management (Pinia Store)
|
179
|
+
|
180
|
+
The framework uses a dynamic store system for managing application state:
|
181
|
+
|
182
|
+
```javascript
|
183
|
+
// Store Structure
|
184
|
+
{
|
185
|
+
mainKey: '', // Current data model key
|
186
|
+
form: {}, // Current form data
|
187
|
+
items: {}, // Data collections by key
|
188
|
+
query: '', // Additional query parameters
|
189
|
+
routes: {}, // API endpoints
|
190
|
+
fields: [], // Field definitions
|
191
|
+
options: [], // Configuration options
|
192
|
+
filters: [], // Active filters
|
193
|
+
loadings: {}, // Loading states
|
194
|
+
dialog: false, // Dialog visibility
|
195
|
+
structure: {}, // Form structure
|
196
|
+
paginations: {}, // Pagination data
|
197
|
+
searchParam: '', // Search query
|
198
|
+
isEditing: false, // Edit mode flag
|
199
|
+
selected: new Set([]) // Selected items
|
200
|
+
}
|
201
|
+
```
|
202
|
+
|
203
|
+
### Event System
|
204
|
+
|
205
|
+
Uses mitt.js for event communication between components:
|
206
|
+
|
207
|
+
```javascript
|
208
|
+
import { emitter } from '@/helpers/emitter'
|
209
|
+
|
210
|
+
// Listen to events
|
211
|
+
emitter.listen('saveForm', () => {
|
212
|
+
// Handle form save
|
213
|
+
})
|
214
|
+
|
215
|
+
// Emit events
|
216
|
+
emitter.event('alert', { text: 'Success!', color: 'green' })
|
217
|
+
```
|
218
|
+
|
219
|
+
### Permission System
|
220
|
+
|
221
|
+
Role-based access control for UI elements:
|
222
|
+
|
223
|
+
```javascript
|
224
|
+
import { usePermission } from '@/composables/usePermission'
|
225
|
+
|
226
|
+
const { can } = usePermission()
|
227
|
+
|
228
|
+
// Check permissions
|
229
|
+
if (can('create')) {
|
230
|
+
// Show create button
|
231
|
+
}
|
232
|
+
```
|
233
|
+
|
234
|
+
## API Reference
|
235
|
+
|
236
|
+
### Field Types
|
237
|
+
|
238
|
+
#### Text Field
|
239
|
+
|
240
|
+
```javascript
|
241
|
+
{
|
242
|
+
type: 'text',
|
243
|
+
title: 'Field Name',
|
244
|
+
placeholder: 'Enter value',
|
245
|
+
required: true,
|
246
|
+
validation: 'required|min:3'
|
247
|
+
}
|
248
|
+
```
|
249
|
+
|
250
|
+
#### Select Field
|
251
|
+
|
252
|
+
```javascript
|
253
|
+
{
|
254
|
+
type: 'select',
|
255
|
+
title: 'Category',
|
256
|
+
items: [
|
257
|
+
{ value: 1, text: 'Option 1' },
|
258
|
+
{ value: 2, text: 'Option 2' }
|
259
|
+
],
|
260
|
+
'label-prop': 'text',
|
261
|
+
'value-prop': 'value',
|
262
|
+
search: true
|
263
|
+
}
|
264
|
+
```
|
265
|
+
|
266
|
+
#### Date Field
|
267
|
+
|
268
|
+
```javascript
|
269
|
+
{
|
270
|
+
type: 'date',
|
271
|
+
title: 'Date',
|
272
|
+
placeholder: 'Select date',
|
273
|
+
format: 'YYYY-MM-DD'
|
274
|
+
}
|
275
|
+
```
|
276
|
+
|
277
|
+
### Store Actions
|
278
|
+
|
279
|
+
#### Data Operations
|
280
|
+
|
281
|
+
```javascript
|
282
|
+
// Load items
|
283
|
+
store.loadItems(key, page)
|
284
|
+
|
285
|
+
// Add new item
|
286
|
+
store.addItem(data)
|
287
|
+
|
288
|
+
// Edit existing item
|
289
|
+
store.editItem(data)
|
290
|
+
|
291
|
+
// Remove item
|
292
|
+
store.remove(id)
|
293
|
+
|
294
|
+
// Reload data
|
295
|
+
store.reloadData()
|
296
|
+
```
|
297
|
+
|
298
|
+
#### Filtering
|
299
|
+
|
300
|
+
```javascript
|
301
|
+
// Apply filters
|
302
|
+
store.loadItems()
|
303
|
+
|
304
|
+
// Clear all filters
|
305
|
+
store.filters = []
|
306
|
+
|
307
|
+
// Generate filter query
|
308
|
+
store.convertToFilterForm()
|
309
|
+
```
|
310
|
+
|
311
|
+
### Composables
|
312
|
+
|
313
|
+
#### useDynamicStore
|
314
|
+
|
315
|
+
```javascript
|
316
|
+
import { useDynamicStore } from '@/composables/useDynamicStore'
|
317
|
+
|
318
|
+
const store = useDynamicStore('MyStore')
|
319
|
+
```
|
320
|
+
|
321
|
+
#### usePermission
|
322
|
+
|
323
|
+
```javascript
|
324
|
+
import { usePermission } from '@/composables/usePermission'
|
325
|
+
|
326
|
+
const { can, setPermissions } = usePermission()
|
327
|
+
|
328
|
+
setPermissions(['create', 'update', 'delete'])
|
28
329
|
```
|
29
330
|
|
30
|
-
|
331
|
+
#### useFetch
|
31
332
|
|
32
|
-
```
|
333
|
+
```javascript
|
334
|
+
import { useFetch } from '@/composables/useFetch'
|
335
|
+
|
336
|
+
const { get, post, patch, remove } = useFetch()
|
337
|
+
|
338
|
+
const response = await get('/api/users')
|
339
|
+
```
|
340
|
+
|
341
|
+
## Usage Examples
|
342
|
+
|
343
|
+
### Basic CRUD Setup
|
344
|
+
|
345
|
+
```vue
|
346
|
+
<template>
|
347
|
+
<MCrud :fields="userFields" :route="userRoutes" :options="{ formMode: 'dialog' }" />
|
348
|
+
</template>
|
349
|
+
|
350
|
+
<script setup>
|
351
|
+
const userFields = {
|
352
|
+
name: {
|
353
|
+
type: 'text',
|
354
|
+
title: 'Full Name',
|
355
|
+
required: true,
|
356
|
+
showIn: ['create', 'edit', 'list']
|
357
|
+
},
|
358
|
+
email: {
|
359
|
+
type: 'email',
|
360
|
+
title: 'Email Address',
|
361
|
+
required: true
|
362
|
+
},
|
363
|
+
role: {
|
364
|
+
type: 'select',
|
365
|
+
title: 'Role',
|
366
|
+
items: [
|
367
|
+
{ value: 'admin', text: 'Administrator' },
|
368
|
+
{ value: 'user', text: 'Regular User' }
|
369
|
+
]
|
370
|
+
},
|
371
|
+
created_at: {
|
372
|
+
type: 'date',
|
373
|
+
title: 'Created Date',
|
374
|
+
showIn: ['list']
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
const userRoutes = {
|
379
|
+
index: '/api/users',
|
380
|
+
create: '/api/users',
|
381
|
+
update: '/api/users',
|
382
|
+
delete: '/api/users'
|
383
|
+
}
|
384
|
+
</script>
|
385
|
+
```
|
386
|
+
|
387
|
+
### Custom Field with API Integration
|
388
|
+
|
389
|
+
```javascript
|
390
|
+
const productFields = {
|
391
|
+
category_id: {
|
392
|
+
type: 'select',
|
393
|
+
title: 'Category',
|
394
|
+
items: async (search) => {
|
395
|
+
const response = await axios.get(`/api/categories?search=${search}`)
|
396
|
+
return response.data.data
|
397
|
+
},
|
398
|
+
'label-prop': 'name',
|
399
|
+
'value-prop': 'id',
|
400
|
+
search: true
|
401
|
+
}
|
402
|
+
}
|
403
|
+
```
|
404
|
+
|
405
|
+
### Advanced Filtering Setup
|
406
|
+
|
407
|
+
```javascript
|
408
|
+
const advancedFields = {
|
409
|
+
status: {
|
410
|
+
type: 'select',
|
411
|
+
title: 'Status',
|
412
|
+
items: [
|
413
|
+
{ value: 'active', text: 'Active' },
|
414
|
+
{ value: 'inactive', text: 'Inactive' }
|
415
|
+
],
|
416
|
+
filterItems: [
|
417
|
+
{ value: 'active', text: 'Active Only' },
|
418
|
+
{ value: 'inactive', text: 'Inactive Only' }
|
419
|
+
]
|
420
|
+
},
|
421
|
+
created_at: {
|
422
|
+
type: 'date',
|
423
|
+
title: 'Created Date',
|
424
|
+
filterable: true
|
425
|
+
}
|
426
|
+
}
|
427
|
+
```
|
428
|
+
|
429
|
+
### Custom Actions
|
430
|
+
|
431
|
+
```vue
|
432
|
+
<template>
|
433
|
+
<MCrud :fields="fields" :route="route" @mounted="setupCustomActions">
|
434
|
+
<template #extra>
|
435
|
+
<CustomActionButtons />
|
436
|
+
</template>
|
437
|
+
</MCrud>
|
438
|
+
</template>
|
439
|
+
|
440
|
+
<script setup>
|
441
|
+
import { emitter } from '@/helpers/emitter'
|
442
|
+
|
443
|
+
const setupCustomActions = () => {
|
444
|
+
emitter.listen('customAction', (data) => {
|
445
|
+
// Handle custom action
|
446
|
+
console.log('Custom action triggered:', data)
|
447
|
+
})
|
448
|
+
}
|
449
|
+
</script>
|
450
|
+
```
|
451
|
+
|
452
|
+
## Advanced Features
|
453
|
+
|
454
|
+
### Batch Operations
|
455
|
+
|
456
|
+
```javascript
|
457
|
+
// Select multiple items
|
458
|
+
store.selected.add(itemId)
|
459
|
+
|
460
|
+
// Batch delete
|
461
|
+
const selectedIds = Array.from(store.selected)
|
462
|
+
store.remove(selectedIds)
|
463
|
+
|
464
|
+
// Custom batch operation
|
465
|
+
emitter.listen('batchUpdate', (data) => {
|
466
|
+
const selectedItems = store.mainItems.filter((item) => store.selected.has(item.id))
|
467
|
+
// Process selected items
|
468
|
+
})
|
469
|
+
```
|
470
|
+
|
471
|
+
### Export Functionality
|
472
|
+
|
473
|
+
```javascript
|
474
|
+
// Export filtered data
|
475
|
+
function exportData() {
|
476
|
+
const exportUrl = store.generateQuery() + '/export'
|
477
|
+
window.open(exportUrl)
|
478
|
+
}
|
479
|
+
|
480
|
+
// Custom export format
|
481
|
+
function exportCustom() {
|
482
|
+
const selectedData = store.mainItems.filter((item) => store.selected.has(item.id))
|
483
|
+
// Process and export selected data
|
484
|
+
}
|
485
|
+
```
|
486
|
+
|
487
|
+
### Custom Column Rendering
|
488
|
+
|
489
|
+
```javascript
|
490
|
+
const customFields = {
|
491
|
+
avatar: {
|
492
|
+
type: 'image',
|
493
|
+
title: 'Avatar',
|
494
|
+
formatter: (value) => {
|
495
|
+
return `<img src="${value}" alt="Avatar" class="w-8 h-8 rounded-full">`
|
496
|
+
}
|
497
|
+
},
|
498
|
+
status: {
|
499
|
+
type: 'select',
|
500
|
+
title: 'Status',
|
501
|
+
formatter: (value) => {
|
502
|
+
const color = value === 'active' ? 'green' : 'red'
|
503
|
+
return `<span class="px-2 py-1 text-xs rounded bg-${color}-100 text-${color}-800">${value}</span>`
|
504
|
+
}
|
505
|
+
}
|
506
|
+
}
|
507
|
+
```
|
508
|
+
|
509
|
+
### Conditional Field Display
|
510
|
+
|
511
|
+
```javascript
|
512
|
+
const conditionalFields = {
|
513
|
+
type: {
|
514
|
+
type: 'select',
|
515
|
+
title: 'User Type',
|
516
|
+
items: [
|
517
|
+
{ value: 'individual', text: 'Individual' },
|
518
|
+
{ value: 'company', text: 'Company' }
|
519
|
+
],
|
520
|
+
onChange: (value, formData) => {
|
521
|
+
// Show/hide fields based on selection
|
522
|
+
if (value === 'company') {
|
523
|
+
// Show company-specific fields
|
524
|
+
}
|
525
|
+
}
|
526
|
+
},
|
527
|
+
company_name: {
|
528
|
+
type: 'text',
|
529
|
+
title: 'Company Name',
|
530
|
+
showIf: (formData) => formData.type === 'company'
|
531
|
+
}
|
532
|
+
}
|
533
|
+
```
|
534
|
+
|
535
|
+
## Customization
|
536
|
+
|
537
|
+
### Styling
|
538
|
+
|
539
|
+
The framework uses Tailwind CSS for styling. You can customize the appearance by:
|
540
|
+
|
541
|
+
1. **Override CSS Classes:**
|
542
|
+
|
543
|
+
```css
|
544
|
+
.fc-header-icon-btn {
|
545
|
+
@apply bg-blue-500 hover:bg-blue-600 text-white;
|
546
|
+
}
|
547
|
+
|
548
|
+
.fc-table-row:hover {
|
549
|
+
@apply bg-blue-50;
|
550
|
+
}
|
551
|
+
```
|
552
|
+
|
553
|
+
2. **Custom Themes:**
|
554
|
+
|
555
|
+
```javascript
|
556
|
+
const customOptions = {
|
557
|
+
theme: {
|
558
|
+
primary: 'blue',
|
559
|
+
secondary: 'gray',
|
560
|
+
success: 'green',
|
561
|
+
danger: 'red'
|
562
|
+
}
|
563
|
+
}
|
564
|
+
```
|
565
|
+
|
566
|
+
### Custom Components
|
567
|
+
|
568
|
+
```vue
|
569
|
+
<!-- CustomField.vue -->
|
570
|
+
<template>
|
571
|
+
<div class="custom-field">
|
572
|
+
<label>{{ field.title }}</label>
|
573
|
+
<input v-model="modelValue" :type="field.type" :placeholder="field.placeholder" />
|
574
|
+
</div>
|
575
|
+
</template>
|
576
|
+
|
577
|
+
<script setup>
|
578
|
+
import { registerFields } from 'formue-crud'
|
579
|
+
|
580
|
+
registerFields({
|
581
|
+
'custom-field': CustomField
|
582
|
+
})
|
583
|
+
</script>
|
584
|
+
```
|
585
|
+
|
586
|
+
### API Response Format
|
587
|
+
|
588
|
+
Expected API response format:
|
589
|
+
|
590
|
+
```json
|
591
|
+
{
|
592
|
+
"data": [
|
593
|
+
{
|
594
|
+
"id": 1,
|
595
|
+
"name": "John Doe",
|
596
|
+
"email": "john@example.com"
|
597
|
+
}
|
598
|
+
],
|
599
|
+
"current_page": 1,
|
600
|
+
"last_page": 5,
|
601
|
+
"total": 50,
|
602
|
+
"per_page": 10
|
603
|
+
}
|
604
|
+
```
|
605
|
+
|
606
|
+
## Best Practices
|
607
|
+
|
608
|
+
### 1. Field Organization
|
609
|
+
|
610
|
+
```javascript
|
611
|
+
// Group related fields
|
612
|
+
const userFields = {
|
613
|
+
// Personal Information
|
614
|
+
first_name: { type: 'text', title: 'First Name', group: 'personal' },
|
615
|
+
last_name: { type: 'text', title: 'Last Name', group: 'personal' },
|
616
|
+
|
617
|
+
// Contact Information
|
618
|
+
email: { type: 'email', title: 'Email', group: 'contact' },
|
619
|
+
phone: { type: 'tel', title: 'Phone', group: 'contact' }
|
620
|
+
}
|
621
|
+
```
|
622
|
+
|
623
|
+
### 2. Performance Optimization
|
624
|
+
|
625
|
+
```javascript
|
626
|
+
// Use lazy loading for large datasets
|
627
|
+
const lazyFields = {
|
628
|
+
category: {
|
629
|
+
type: 'select',
|
630
|
+
items: async (search) => {
|
631
|
+
// Only load when needed
|
632
|
+
if (search.length < 2) return []
|
633
|
+
return await fetchCategories(search)
|
634
|
+
}
|
635
|
+
}
|
636
|
+
}
|
637
|
+
```
|
638
|
+
|
639
|
+
### 3. Error Handling
|
640
|
+
|
641
|
+
```javascript
|
642
|
+
// Global error handling
|
643
|
+
emitter.listen('error', (error) => {
|
644
|
+
console.error('CRUD Error:', error)
|
645
|
+
// Show user-friendly message
|
646
|
+
showNotification(error.message, 'error')
|
647
|
+
})
|
648
|
+
```
|
649
|
+
|
650
|
+
### 4. Validation
|
651
|
+
|
652
|
+
```javascript
|
653
|
+
const validatedFields = {
|
654
|
+
email: {
|
655
|
+
type: 'email',
|
656
|
+
title: 'Email',
|
657
|
+
rules: ['required', 'email'],
|
658
|
+
messages: {
|
659
|
+
required: 'Email is required',
|
660
|
+
email: 'Please enter a valid email'
|
661
|
+
}
|
662
|
+
}
|
663
|
+
}
|
664
|
+
```
|
665
|
+
|
666
|
+
## Troubleshooting
|
667
|
+
|
668
|
+
### Common Issues
|
669
|
+
|
670
|
+
#### 1. Data Not Loading
|
671
|
+
|
672
|
+
```javascript
|
673
|
+
// Check API endpoint
|
674
|
+
console.log('API URL:', store.generateRoute())
|
675
|
+
|
676
|
+
// Verify response format
|
677
|
+
axios.get('/api/users').then((response) => {
|
678
|
+
console.log('Response structure:', response.data)
|
679
|
+
})
|
680
|
+
```
|
681
|
+
|
682
|
+
#### 2. Form Validation Errors
|
683
|
+
|
684
|
+
```javascript
|
685
|
+
// Debug form validation
|
686
|
+
emitter.listen('validation-error', (errors) => {
|
687
|
+
console.log('Validation errors:', errors)
|
688
|
+
})
|
689
|
+
```
|
690
|
+
|
691
|
+
#### 3. Permission Issues
|
692
|
+
|
693
|
+
```javascript
|
694
|
+
// Check permission setup
|
695
|
+
const { permissions } = usePermission()
|
696
|
+
console.log('Available permissions:', permissions.value)
|
697
|
+
```
|
698
|
+
|
699
|
+
#### 4. Filter Not Working
|
700
|
+
|
701
|
+
```javascript
|
702
|
+
// Debug filter generation
|
703
|
+
console.log('Filter query:', store.convertToFilterForm())
|
704
|
+
```
|
705
|
+
|
706
|
+
### Debug Mode
|
707
|
+
|
708
|
+
Enable debug mode for detailed logging:
|
709
|
+
|
710
|
+
```javascript
|
711
|
+
const debugOptions = {
|
712
|
+
debug: true,
|
713
|
+
logging: {
|
714
|
+
api: true,
|
715
|
+
events: true,
|
716
|
+
state: true
|
717
|
+
}
|
718
|
+
}
|
719
|
+
```
|
720
|
+
|
721
|
+
### Performance Monitoring
|
722
|
+
|
723
|
+
```javascript
|
724
|
+
// Monitor API calls
|
725
|
+
axios.interceptors.request.use((request) => {
|
726
|
+
console.time(`API: ${request.url}`)
|
727
|
+
return request
|
728
|
+
})
|
729
|
+
|
730
|
+
axios.interceptors.response.use((response) => {
|
731
|
+
console.timeEnd(`API: ${response.config.url}`)
|
732
|
+
return response
|
733
|
+
})
|
734
|
+
```
|
735
|
+
|
736
|
+
## Migration Guide
|
737
|
+
|
738
|
+
### From Version 0.1.x to 0.2.x
|
739
|
+
|
740
|
+
1. **Update field definitions:**
|
741
|
+
|
742
|
+
```javascript
|
743
|
+
// Old format
|
744
|
+
const fields = [{ field: 'name', type: 'text', title: 'Name' }]
|
745
|
+
|
746
|
+
// New format
|
747
|
+
const fields = {
|
748
|
+
name: { type: 'text', title: 'Name' }
|
749
|
+
}
|
750
|
+
```
|
751
|
+
|
752
|
+
2. **Update event listeners:**
|
753
|
+
|
754
|
+
```javascript
|
755
|
+
// Old format
|
756
|
+
this.$emit('update', data)
|
757
|
+
|
758
|
+
// New format
|
759
|
+
emitter.event('update', data)
|
760
|
+
```
|
761
|
+
|
762
|
+
## Contributing
|
763
|
+
|
764
|
+
### Development Setup
|
765
|
+
|
766
|
+
```bash
|
767
|
+
git clone https://github.com/your-repo/formue-crud
|
768
|
+
cd formue-crud
|
769
|
+
npm install
|
33
770
|
npm run dev
|
34
771
|
```
|
35
772
|
|
36
|
-
###
|
773
|
+
### Build Process
|
37
774
|
|
38
|
-
```
|
775
|
+
```bash
|
39
776
|
npm run build
|
777
|
+
npm run type-check
|
778
|
+
npm run lint
|
40
779
|
```
|
41
780
|
|
42
|
-
###
|
781
|
+
### Testing
|
43
782
|
|
44
|
-
```
|
45
|
-
npm run
|
783
|
+
```bash
|
784
|
+
npm run test
|
785
|
+
npm run test:unit
|
786
|
+
npm run test:e2e
|
46
787
|
```
|
788
|
+
|
789
|
+
---
|
790
|
+
|
791
|
+
**Version:** 0.1.77
|
792
|
+
**Last Updated:** 2024
|
793
|
+
**License:** MIT
|
794
|
+
|
795
|
+
For more information, visit the [GitHub repository](https://github.com/your-repo/formue-crud) or contact the maintainers.
|