@djangocfg/layouts 1.2.39 → 1.2.41
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/package.json +5 -5
- package/src/layouts/AppLayout/AppLayout.tsx +16 -7
- package/src/layouts/AppLayout/components/PackageVersions/packageVersions.config.ts +8 -8
- package/src/layouts/AppLayout/providers/CoreProviders.tsx +28 -9
- package/src/validation/README.md +145 -547
- package/src/validation/components/ErrorButtons.tsx +100 -0
- package/src/validation/components/ErrorToast.tsx +159 -0
- package/src/validation/hooks.ts +10 -0
- package/src/validation/index.ts +31 -23
- package/src/validation/providers/ErrorTrackingProvider.tsx +265 -0
- package/src/validation/types.ts +278 -0
- package/src/validation/utils/formatters.ts +114 -0
- package/src/validation/REFACTORING.md +0 -162
- package/src/validation/ValidationErrorButtons.tsx +0 -80
- package/src/validation/ValidationErrorContext.tsx +0 -333
- package/src/validation/ValidationErrorToast.tsx +0 -181
- /package/src/validation/{curl-generator.ts → utils/curl-generator.ts} +0 -0
package/src/validation/README.md
CHANGED
|
@@ -1,593 +1,191 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Error Tracking System
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Universal error tracking for React apps with automatic toast notifications.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
✅ **Auto-capture validation errors** from API client via CustomEvent
|
|
10
|
-
✅ **Toast notifications** with destructive styling
|
|
11
|
-
✅ **Copy Error button** - One-click copy full error details JSON to clipboard
|
|
12
|
-
✅ **Copy cURL button** - Generate and copy cURL command with auth token
|
|
13
|
-
✅ **Error history** - Store and manage validation errors
|
|
14
|
-
✅ **Configurable** - Customize display and behavior
|
|
15
|
-
✅ **Type-safe** - Full TypeScript support
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## Quick Start
|
|
20
|
-
|
|
21
|
-
### 1. Setup Provider
|
|
5
|
+
## The Essence
|
|
22
6
|
|
|
23
|
-
|
|
7
|
+
One provider that listens to browser `CustomEvent`s from API client and shows toast notifications automatically:
|
|
24
8
|
|
|
25
9
|
```tsx
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<ValidationErrorProvider>
|
|
32
|
-
{children}
|
|
33
|
-
</ValidationErrorProvider>
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 2. Trigger Validation Error
|
|
39
|
-
|
|
40
|
-
Use the test button in UILayout header:
|
|
41
|
-
|
|
42
|
-
```tsx
|
|
43
|
-
// In UILayout header, click "Test Validation" button
|
|
44
|
-
// Select any error type (Simple, Multiple, Nested, Array)
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Or dispatch manually:
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import type { ValidationErrorDetail } from '@djangocfg/layouts/validation';
|
|
51
|
-
|
|
52
|
-
const errorDetail: ValidationErrorDetail = {
|
|
53
|
-
operation: 'createUser',
|
|
54
|
-
path: '/api/users',
|
|
55
|
-
method: 'POST',
|
|
56
|
-
error: zodError, // ZodError instance
|
|
57
|
-
response: responseData,
|
|
58
|
-
timestamp: new Date(),
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
window.dispatchEvent(new CustomEvent('zod-validation-error', {
|
|
62
|
-
detail: errorDetail,
|
|
63
|
-
bubbles: true,
|
|
64
|
-
cancelable: false,
|
|
65
|
-
}));
|
|
66
|
-
```
|
|
10
|
+
// Setup once
|
|
11
|
+
<ErrorTrackingProvider>
|
|
12
|
+
<App />
|
|
13
|
+
</ErrorTrackingProvider>
|
|
67
14
|
|
|
68
|
-
|
|
15
|
+
// API client dispatches events
|
|
16
|
+
window.dispatchEvent(new CustomEvent('zod-validation-error', { detail: {...} }));
|
|
17
|
+
window.dispatchEvent(new CustomEvent('cors-error', { detail: {...} }));
|
|
18
|
+
window.dispatchEvent(new CustomEvent('network-error', { detail: {...} }));
|
|
69
19
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- **Description**: Endpoint, error count, first 3 errors
|
|
73
|
-
- **Two Buttons** (displayed at bottom):
|
|
74
|
-
- **📋 Copy Error** - Copies full error JSON to clipboard
|
|
75
|
-
- **🔄 Copy cURL** - Generates and copies cURL command with auth token
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Toast with Copy Button
|
|
80
|
-
|
|
81
|
-
The system automatically shows toasts with a copy button for all validation errors.
|
|
82
|
-
|
|
83
|
-
### What Gets Copied
|
|
84
|
-
|
|
85
|
-
When you click "📋 Copy", the following JSON is copied to clipboard:
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
{
|
|
89
|
-
"timestamp": "2025-11-11T00:39:22.123Z",
|
|
90
|
-
"operation": "createUser",
|
|
91
|
-
"endpoint": {
|
|
92
|
-
"method": "POST",
|
|
93
|
-
"path": "/api/users"
|
|
94
|
-
},
|
|
95
|
-
"validation_errors": [
|
|
96
|
-
{
|
|
97
|
-
"path": "email",
|
|
98
|
-
"message": "Invalid email format",
|
|
99
|
-
"code": "invalid_string",
|
|
100
|
-
"expected": "email",
|
|
101
|
-
"received": "string"
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
"path": "age",
|
|
105
|
-
"message": "Number must be greater than 0",
|
|
106
|
-
"code": "too_small",
|
|
107
|
-
"minimum": 0
|
|
108
|
-
}
|
|
109
|
-
],
|
|
110
|
-
"response": {
|
|
111
|
-
"email": "not-an-email",
|
|
112
|
-
"age": -5
|
|
113
|
-
},
|
|
114
|
-
"total_errors": 2
|
|
115
|
-
}
|
|
20
|
+
// Provider catches them → shows toast → stores in state
|
|
21
|
+
const { errors } = useErrors();
|
|
116
22
|
```
|
|
117
23
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- **Success**: Shows "✅ Copied! Error details copied to clipboard" for 2 seconds
|
|
121
|
-
- **Error**: Shows "❌ Copy failed - Could not copy error details" for 2 seconds
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## Configuration
|
|
126
|
-
|
|
127
|
-
### Provider Config
|
|
24
|
+
## Quick Start
|
|
128
25
|
|
|
129
26
|
```tsx
|
|
130
|
-
|
|
131
|
-
config={{
|
|
132
|
-
enableToast: true, // Show toast notifications
|
|
133
|
-
maxErrors: 50, // Max errors to store in history
|
|
134
|
-
toastSettings: {
|
|
135
|
-
duration: 5000, // Toast duration in ms
|
|
136
|
-
showOperation: true, // Show operation name in title
|
|
137
|
-
showPath: true, // Show endpoint path in description
|
|
138
|
-
showErrorCount: true, // Show error count in description
|
|
139
|
-
},
|
|
140
|
-
onError: (detail) => {
|
|
141
|
-
// Custom error handler
|
|
142
|
-
console.error('Validation error:', detail);
|
|
143
|
-
// Return false to prevent toast
|
|
144
|
-
return true;
|
|
145
|
-
},
|
|
146
|
-
}}
|
|
147
|
-
>
|
|
148
|
-
{children}
|
|
149
|
-
</ValidationErrorProvider>
|
|
150
|
-
```
|
|
27
|
+
import { ErrorTrackingProvider, useErrors } from '@djangocfg/layouts';
|
|
151
28
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
29
|
+
// 1. Wrap your app
|
|
30
|
+
<ErrorTrackingProvider
|
|
31
|
+
validation={{ enabled: true, showToast: true }}
|
|
32
|
+
cors={{ enabled: true, showToast: true }}
|
|
33
|
+
network={{ enabled: false }}
|
|
34
|
+
>
|
|
35
|
+
<App />
|
|
36
|
+
</ErrorTrackingProvider>
|
|
159
37
|
|
|
38
|
+
// 2. Access errors anywhere
|
|
160
39
|
function MyComponent() {
|
|
161
|
-
const {
|
|
162
|
-
|
|
163
|
-
const handleError = (errorDetail: ValidationErrorDetail) => {
|
|
164
|
-
const toastOptions = createValidationErrorToast(errorDetail, {
|
|
165
|
-
config: {
|
|
166
|
-
showOperation: true,
|
|
167
|
-
showPath: true,
|
|
168
|
-
showErrorCount: true,
|
|
169
|
-
maxIssuesInDescription: 5, // Show up to 5 errors
|
|
170
|
-
titlePrefix: '🚨 API Error', // Custom prefix
|
|
171
|
-
},
|
|
172
|
-
duration: 10000, // 10 seconds
|
|
173
|
-
onCopySuccess: () => {
|
|
174
|
-
toast({ title: 'Copied!', duration: 1000 });
|
|
175
|
-
},
|
|
176
|
-
onCopyError: (error) => {
|
|
177
|
-
console.error('Copy failed:', error);
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
toast(toastOptions);
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
return <button onClick={() => handleError(errorDetail)}>Trigger Error</button>;
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## API Reference
|
|
191
|
-
|
|
192
|
-
### `ValidationErrorProvider`
|
|
40
|
+
const { errors, validationErrors, corsErrors, clearErrors } = useErrors();
|
|
193
41
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
**Props:**
|
|
197
|
-
```typescript
|
|
198
|
-
interface ValidationErrorProviderProps {
|
|
199
|
-
children: ReactNode;
|
|
200
|
-
config?: Partial<ValidationErrorConfig>;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
interface ValidationErrorConfig {
|
|
204
|
-
enableToast: boolean; // Default: true
|
|
205
|
-
maxErrors: number; // Default: 50
|
|
206
|
-
toastSettings: {
|
|
207
|
-
duration: number; // Default: 5000ms
|
|
208
|
-
showOperation: boolean; // Default: true
|
|
209
|
-
showPath: boolean; // Default: true
|
|
210
|
-
showErrorCount: boolean; // Default: true
|
|
211
|
-
};
|
|
212
|
-
onError?: (detail: ValidationErrorDetail) => boolean | void;
|
|
42
|
+
return <div>Total errors: {errors.length}</div>;
|
|
213
43
|
}
|
|
214
44
|
```
|
|
215
45
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
### `useValidationErrors()`
|
|
46
|
+
## Error Types
|
|
219
47
|
|
|
220
|
-
|
|
48
|
+
| Type | Event Name | Source | Toast Content |
|
|
49
|
+
|------|-----------|--------|---------------|
|
|
50
|
+
| **Validation** | `zod-validation-error` | API client Zod schema validation | Field errors, copy buttons |
|
|
51
|
+
| **CORS** | `cors-error` | API client CORS blocked | Causes, solutions, troubleshooting |
|
|
52
|
+
| **Network** | `network-error` | API client network issues | Error details, status code |
|
|
221
53
|
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
interface ValidationErrorContextValue {
|
|
225
|
-
errors: StoredValidationError[]; // All errors in history
|
|
226
|
-
clearErrors: () => void; // Clear all errors
|
|
227
|
-
clearError: (id: string) => void; // Clear specific error
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
**Usage:**
|
|
232
|
-
```typescript
|
|
233
|
-
import { useValidationErrors } from '@djangocfg/layouts/validation';
|
|
234
|
-
|
|
235
|
-
function ErrorList() {
|
|
236
|
-
const { errors, clearErrors, clearError } = useValidationErrors();
|
|
237
|
-
|
|
238
|
-
return (
|
|
239
|
-
<div>
|
|
240
|
-
<button onClick={clearErrors}>Clear All</button>
|
|
241
|
-
{errors.map((error) => (
|
|
242
|
-
<div key={error.id}>
|
|
243
|
-
<p>{error.operation}: {error.error.issues.length} errors</p>
|
|
244
|
-
<button onClick={() => clearError(error.id)}>Clear</button>
|
|
245
|
-
</div>
|
|
246
|
-
))}
|
|
247
|
-
</div>
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
### `createValidationErrorToast()`
|
|
255
|
-
|
|
256
|
-
Create custom toast options with copy button.
|
|
257
|
-
|
|
258
|
-
**Signature:**
|
|
259
|
-
```typescript
|
|
260
|
-
function createValidationErrorToast(
|
|
261
|
-
detail: ValidationErrorDetail,
|
|
262
|
-
options?: {
|
|
263
|
-
config?: Partial<ValidationErrorToastConfig>;
|
|
264
|
-
duration?: number;
|
|
265
|
-
onCopySuccess?: () => void;
|
|
266
|
-
onCopyError?: (error: Error) => void;
|
|
267
|
-
}
|
|
268
|
-
): ToastOptions
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
**Returns:** Object with `title`, `description`, `variant`, `duration`, `action` (copy button)
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
### `formatErrorForClipboard()`
|
|
276
|
-
|
|
277
|
-
Format error details as JSON for clipboard.
|
|
278
|
-
|
|
279
|
-
**Signature:**
|
|
280
|
-
```typescript
|
|
281
|
-
function formatErrorForClipboard(detail: ValidationErrorDetail): string
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
**Returns:** Formatted JSON string with all error details
|
|
285
|
-
|
|
286
|
-
---
|
|
287
|
-
|
|
288
|
-
### `createCopyAction()`
|
|
289
|
-
|
|
290
|
-
Create standalone copy button for toast.
|
|
291
|
-
|
|
292
|
-
**Signature:**
|
|
293
|
-
```typescript
|
|
294
|
-
function createCopyAction(
|
|
295
|
-
detail: ValidationErrorDetail,
|
|
296
|
-
onCopySuccess?: () => void,
|
|
297
|
-
onCopyError?: (error: Error) => void
|
|
298
|
-
): React.ReactElement
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
**Returns:** `<ToastAction>` component with copy functionality
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## Testing
|
|
306
|
-
|
|
307
|
-
### Test Button in UILayout
|
|
308
|
-
|
|
309
|
-
The `TestValidationButton` in UILayout header provides 4 test scenarios:
|
|
310
|
-
|
|
311
|
-
1. **Simple Error** - Single field validation (email)
|
|
312
|
-
2. **Multiple Errors** - 3 validation errors (email, age, username)
|
|
313
|
-
3. **Nested Object** - Nested property errors (address.street, address.zipCode)
|
|
314
|
-
4. **Array Validation** - Array item errors (items[0].quantity, items[1].price)
|
|
315
|
-
|
|
316
|
-
Each test:
|
|
317
|
-
- Dispatches CustomEvent
|
|
318
|
-
- Triggers toast with copy button
|
|
319
|
-
- Logs to console
|
|
320
|
-
|
|
321
|
-
---
|
|
322
|
-
|
|
323
|
-
## Browser Compatibility
|
|
324
|
-
|
|
325
|
-
### Clipboard API
|
|
326
|
-
|
|
327
|
-
**Modern browsers** (Chrome 66+, Firefox 63+, Safari 13.1+):
|
|
328
|
-
- Uses `navigator.clipboard.writeText()` (async)
|
|
329
|
-
|
|
330
|
-
**Older browsers**:
|
|
331
|
-
- Fallback to `document.execCommand('copy')`
|
|
332
|
-
|
|
333
|
-
---
|
|
334
|
-
|
|
335
|
-
## Examples
|
|
336
|
-
|
|
337
|
-
### Example 1: Basic Setup
|
|
54
|
+
## Props
|
|
338
55
|
|
|
339
56
|
```tsx
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
### Example 2: Custom Error Handler
|
|
352
|
-
|
|
353
|
-
```tsx
|
|
354
|
-
<ValidationErrorProvider
|
|
355
|
-
config={{
|
|
356
|
-
onError: (detail) => {
|
|
357
|
-
// Log to external service
|
|
358
|
-
logToSentry(detail);
|
|
359
|
-
|
|
360
|
-
// Only show toast for POST/PUT/PATCH errors
|
|
361
|
-
return ['POST', 'PUT', 'PATCH'].includes(detail.method);
|
|
362
|
-
},
|
|
57
|
+
<ErrorTrackingProvider
|
|
58
|
+
validation={{
|
|
59
|
+
enabled: true, // Enable tracking
|
|
60
|
+
showToast: true, // Show toast
|
|
61
|
+
maxErrors: 50, // Max history
|
|
62
|
+
duration: 8000, // Toast duration (ms)
|
|
63
|
+
showOperation: true, // Show operation name
|
|
64
|
+
showPath: true, // Show API path
|
|
65
|
+
showErrorCount: true, // Show error count
|
|
66
|
+
maxIssuesInToast: 3 // Max issues in toast
|
|
363
67
|
}}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const toastOptions = createValidationErrorToast({
|
|
384
|
-
operation: 'createUser',
|
|
385
|
-
path: '/api/users',
|
|
386
|
-
method: 'POST',
|
|
387
|
-
error: error,
|
|
388
|
-
response: data,
|
|
389
|
-
timestamp: new Date(),
|
|
390
|
-
}, {
|
|
391
|
-
onCopySuccess: () => console.log('Copied!'),
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
toast(toastOptions);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
return <form onSubmit={handleSubmit}>...</form>;
|
|
400
|
-
}
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Example 4: Error History Display
|
|
404
|
-
|
|
405
|
-
```tsx
|
|
406
|
-
import { useValidationErrors } from '@djangocfg/layouts/validation';
|
|
407
|
-
|
|
408
|
-
function ErrorHistory() {
|
|
409
|
-
const { errors, clearErrors } = useValidationErrors();
|
|
410
|
-
|
|
411
|
-
return (
|
|
412
|
-
<div className="space-y-4">
|
|
413
|
-
<div className="flex justify-between items-center">
|
|
414
|
-
<h2>Validation Error History ({errors.length})</h2>
|
|
415
|
-
<Button onClick={clearErrors} variant="outline" size="sm">
|
|
416
|
-
Clear All
|
|
417
|
-
</Button>
|
|
418
|
-
</div>
|
|
419
|
-
|
|
420
|
-
{errors.map((error) => (
|
|
421
|
-
<div key={error.id} className="border p-4 rounded">
|
|
422
|
-
<div className="flex justify-between">
|
|
423
|
-
<div>
|
|
424
|
-
<p className="font-semibold">{error.operation}</p>
|
|
425
|
-
<p className="text-sm text-muted-foreground">
|
|
426
|
-
{error.method} {error.path}
|
|
427
|
-
</p>
|
|
428
|
-
</div>
|
|
429
|
-
<p className="text-xs text-muted-foreground">
|
|
430
|
-
{error.timestamp.toLocaleString()}
|
|
431
|
-
</p>
|
|
432
|
-
</div>
|
|
433
|
-
<div className="mt-2">
|
|
434
|
-
<p className="text-sm">
|
|
435
|
-
{error.error.issues.length} validation errors
|
|
436
|
-
</p>
|
|
437
|
-
</div>
|
|
438
|
-
</div>
|
|
439
|
-
))}
|
|
440
|
-
</div>
|
|
441
|
-
);
|
|
442
|
-
}
|
|
68
|
+
cors={{
|
|
69
|
+
enabled: true,
|
|
70
|
+
showToast: true,
|
|
71
|
+
duration: 0, // 0 = no auto-dismiss
|
|
72
|
+
showUrl: true,
|
|
73
|
+
showMethod: true
|
|
74
|
+
}}
|
|
75
|
+
network={{
|
|
76
|
+
enabled: false, // Disabled by default
|
|
77
|
+
showToast: true,
|
|
78
|
+
showUrl: true,
|
|
79
|
+
showMethod: true,
|
|
80
|
+
showStatusCode: true
|
|
81
|
+
}}
|
|
82
|
+
onError={(error) => {
|
|
83
|
+
// Custom handler
|
|
84
|
+
// Return false to prevent toast
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
443
87
|
```
|
|
444
88
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
## Troubleshooting
|
|
448
|
-
|
|
449
|
-
### Toast not showing
|
|
450
|
-
|
|
451
|
-
1. **Check Toaster is rendered**:
|
|
452
|
-
```tsx
|
|
453
|
-
import { Toaster } from '@djangocfg/ui';
|
|
454
|
-
// In your root layout
|
|
455
|
-
<Toaster />
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
2. **Check ValidationErrorProvider is wrapping your app**
|
|
459
|
-
|
|
460
|
-
3. **Check config.enableToast is true**
|
|
461
|
-
|
|
462
|
-
### Copy button not working
|
|
463
|
-
|
|
464
|
-
1. **Check HTTPS**: Clipboard API requires secure context (HTTPS or localhost)
|
|
465
|
-
2. **Check browser permissions**: Some browsers may block clipboard access
|
|
466
|
-
3. **Check console**: Look for clipboard errors
|
|
467
|
-
|
|
468
|
-
### Test button not visible
|
|
469
|
-
|
|
470
|
-
1. **Check NODE_ENV**: Button only shows in development by default
|
|
471
|
-
2. **Override in production**: Pass `showInProduction={true}` to TestValidationButton
|
|
472
|
-
|
|
473
|
-
---
|
|
474
|
-
|
|
475
|
-
## File Structure
|
|
89
|
+
## Structure
|
|
476
90
|
|
|
477
91
|
```
|
|
478
92
|
validation/
|
|
479
|
-
├──
|
|
480
|
-
├──
|
|
481
|
-
├──
|
|
482
|
-
└──
|
|
93
|
+
├── providers/ErrorTrackingProvider.tsx # Single provider
|
|
94
|
+
├── components/
|
|
95
|
+
│ ├── ErrorToast.tsx # Universal toast
|
|
96
|
+
│ └── ErrorButtons.tsx # Copy buttons
|
|
97
|
+
├── utils/
|
|
98
|
+
│ ├── formatters.ts # Format errors
|
|
99
|
+
│ └── curl-generator.ts # Generate cURL
|
|
100
|
+
├── types.ts # TypeScript types
|
|
101
|
+
├── hooks.ts # useErrors()
|
|
102
|
+
└── index.ts # Public API
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## How It Works
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
API Client (TypeScript)
|
|
109
|
+
↓
|
|
110
|
+
Throws Error
|
|
111
|
+
↓
|
|
112
|
+
Dispatches CustomEvent → window.dispatchEvent('zod-validation-error')
|
|
113
|
+
↓
|
|
114
|
+
ErrorTrackingProvider (React)
|
|
115
|
+
↓
|
|
116
|
+
Listens via window.addEventListener()
|
|
117
|
+
↓
|
|
118
|
+
1. Stores error in state
|
|
119
|
+
2. Shows toast notification
|
|
120
|
+
3. Provides via useErrors()
|
|
483
121
|
```
|
|
484
122
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
## Related Components
|
|
488
|
-
|
|
489
|
-
- **TestValidationButton** - Test button in UILayout header
|
|
490
|
-
- **UILayout** - Layout with validation test button
|
|
491
|
-
- **Toaster** - Toast notification container (@djangocfg/ui)
|
|
492
|
-
- **useToast** - Toast hook (@djangocfg/ui)
|
|
123
|
+
## Features
|
|
493
124
|
|
|
494
|
-
|
|
125
|
+
- ✅ **Single provider** for all error types
|
|
126
|
+
- ✅ **Automatic toast** notifications with copy buttons
|
|
127
|
+
- ✅ **Type-safe** TypeScript throughout
|
|
128
|
+
- ✅ **Theme-aware** buttons (no color issues)
|
|
129
|
+
- ✅ **Lucide icons** instead of emojis
|
|
130
|
+
- ✅ **Error history** with filtering by type
|
|
131
|
+
- ✅ **Custom handlers** for logging to Sentry/etc
|
|
132
|
+
- ✅ **SSR-safe** (checks `typeof window`)
|
|
495
133
|
|
|
496
|
-
##
|
|
134
|
+
## Migration from v1
|
|
497
135
|
|
|
498
|
-
|
|
136
|
+
```tsx
|
|
137
|
+
// Before
|
|
138
|
+
<ValidationErrorProvider>
|
|
139
|
+
<CORSErrorProvider>
|
|
140
|
+
<App />
|
|
141
|
+
</CORSErrorProvider>
|
|
142
|
+
</ValidationErrorProvider>
|
|
499
143
|
|
|
500
|
-
|
|
144
|
+
// After
|
|
145
|
+
<ErrorTrackingProvider
|
|
146
|
+
validation={{ ... }}
|
|
147
|
+
cors={{ ... }}
|
|
148
|
+
>
|
|
149
|
+
<App />
|
|
150
|
+
</ErrorTrackingProvider>
|
|
501
151
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
-H 'Content-Type: application/json' \
|
|
506
|
-
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
152
|
+
// Hooks
|
|
153
|
+
useValidationErrors() → useErrors().validationErrors
|
|
154
|
+
useCORSErrors() → useErrors().corsErrors
|
|
507
155
|
```
|
|
508
156
|
|
|
509
|
-
|
|
510
|
-
- ✅ Adds your auth token from localStorage
|
|
511
|
-
- ✅ Formats headers properly
|
|
512
|
-
- ✅ Uses correct HTTP method
|
|
513
|
-
- ✅ Escapes special characters
|
|
514
|
-
|
|
515
|
-
### Token Auto-Detection
|
|
516
|
-
|
|
517
|
-
The cURL generator looks for your token in localStorage:
|
|
518
|
-
- `access_token` (default)
|
|
519
|
-
- `token`
|
|
520
|
-
- `auth_token`
|
|
521
|
-
|
|
522
|
-
### Manual cURL Generation
|
|
157
|
+
## API
|
|
523
158
|
|
|
524
|
-
|
|
159
|
+
### `useErrors()`
|
|
525
160
|
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
//
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
161
|
+
```tsx
|
|
162
|
+
const {
|
|
163
|
+
errors, // All errors
|
|
164
|
+
validationErrors, // Validation only
|
|
165
|
+
corsErrors, // CORS only
|
|
166
|
+
networkErrors, // Network only
|
|
167
|
+
clearErrors, // Clear all
|
|
168
|
+
clearErrorsByType, // Clear by type
|
|
169
|
+
clearError, // Clear one
|
|
170
|
+
errorCount, // Total count
|
|
171
|
+
latestError, // Latest error
|
|
172
|
+
config // Current config
|
|
173
|
+
} = useErrors();
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Event Details
|
|
541
177
|
|
|
542
|
-
|
|
178
|
+
```tsx
|
|
179
|
+
// Validation
|
|
180
|
+
{ type: 'validation', operation, path, method, error: ZodError, response, timestamp }
|
|
543
181
|
|
|
544
|
-
|
|
182
|
+
// CORS
|
|
183
|
+
{ type: 'cors', url, method, error: string, timestamp }
|
|
545
184
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
interface CurlOptions {
|
|
549
|
-
method: string; // HTTP method
|
|
550
|
-
path: string; // API path
|
|
551
|
-
token?: string; // Auth token (auto-fetched if omitted)
|
|
552
|
-
body?: any; // Request body
|
|
553
|
-
headers?: Record<string, string>; // Custom headers
|
|
554
|
-
baseUrl?: string; // API base URL (from env by default)
|
|
555
|
-
}
|
|
185
|
+
// Network
|
|
186
|
+
{ type: 'network', url, method, error: string, statusCode?, timestamp }
|
|
556
187
|
```
|
|
557
188
|
|
|
558
|
-
#### `generateCurlFromError(detail): string`
|
|
559
|
-
|
|
560
|
-
Generate cURL from validation error details. Auto-fetches token from localStorage.
|
|
561
|
-
|
|
562
|
-
#### `getAuthToken(): string | null`
|
|
563
|
-
|
|
564
|
-
Get authentication token from localStorage.
|
|
565
|
-
|
|
566
|
-
#### `copyCurlToClipboard(curl: string): Promise<boolean>`
|
|
567
|
-
|
|
568
|
-
Copy cURL command to clipboard. Returns `true` on success.
|
|
569
|
-
|
|
570
189
|
---
|
|
571
190
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
### 2025-11-11 - v2.1.0
|
|
575
|
-
- ✨ Added **Copy cURL button** with automatic token injection
|
|
576
|
-
- ✨ Added `curl-generator.ts` utilities
|
|
577
|
-
- ✨ Added two buttons layout at bottom of toast
|
|
578
|
-
- ✨ Auto-detect auth token from localStorage
|
|
579
|
-
- 📝 Updated documentation with cURL examples
|
|
580
|
-
|
|
581
|
-
### 2025-11-11 - v2.0.0
|
|
582
|
-
- ✨ Added copy-to-clipboard button in toast
|
|
583
|
-
- ✨ Added `ValidationErrorToast` utilities
|
|
584
|
-
- ✨ Added `formatErrorForClipboard()` function
|
|
585
|
-
- ✨ Added success/error feedback for copy action
|
|
586
|
-
- 📝 Added comprehensive documentation
|
|
587
|
-
|
|
588
|
-
### 2025-11-10 - v1.0.0
|
|
589
|
-
- 🎉 Initial release
|
|
590
|
-
- ✨ ValidationErrorProvider component
|
|
591
|
-
- ✨ useValidationErrors hook
|
|
592
|
-
- ✨ CustomEvent-based error capture
|
|
593
|
-
- ✨ Toast notifications
|
|
191
|
+
**Built with React Context + Browser CustomEvents**
|