@djangocfg/layouts 1.2.32 → 1.2.34
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/auth/context/AuthContext.tsx +15 -1
- package/src/index.ts +4 -1
- package/src/layouts/AppLayout/AppLayout.tsx +9 -2
- package/src/layouts/AppLayout/components/PackageVersions/packageVersions.config.ts +8 -8
- package/src/layouts/AppLayout/layouts/AdminLayout/AdminLayout.tsx +39 -13
- package/src/layouts/AppLayout/layouts/AdminLayout/hooks/useApp.ts +37 -8
- package/src/layouts/AppLayout/providers/CoreProviders.tsx +12 -2
- package/src/layouts/UILayout/components/layout/Header/Header.tsx +11 -4
- package/src/layouts/UILayout/components/layout/Header/HeaderDesktop.tsx +14 -7
- package/src/layouts/UILayout/components/layout/Header/TestValidationButton.tsx +265 -0
- package/src/layouts/UILayout/components/layout/Header/index.ts +2 -0
- package/src/validation/README.md +593 -0
- package/src/validation/REFACTORING.md +162 -0
- package/src/validation/ValidationErrorButtons.tsx +80 -0
- package/src/validation/ValidationErrorContext.tsx +333 -0
- package/src/validation/ValidationErrorToast.tsx +181 -0
- package/src/validation/curl-generator.ts +118 -0
- package/src/validation/index.ts +36 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
# Validation Error System
|
|
2
|
+
|
|
3
|
+
Automatic Zod validation error tracking with toast notifications and copy-to-clipboard functionality.
|
|
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
|
|
22
|
+
|
|
23
|
+
Wrap your app with `ValidationErrorProvider`:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
// apps/admin/src/layouts/RootLayout.tsx
|
|
27
|
+
import { ValidationErrorProvider } from '@djangocfg/layouts/validation';
|
|
28
|
+
|
|
29
|
+
export default function RootLayout({ children }) {
|
|
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
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. See Results
|
|
69
|
+
|
|
70
|
+
You'll see a toast with:
|
|
71
|
+
- **Title**: "❌ Validation Error in operation_name"
|
|
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
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Copy Success/Error Feedback
|
|
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
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<ValidationErrorProvider
|
|
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
|
+
```
|
|
151
|
+
|
|
152
|
+
### Custom Toast Config
|
|
153
|
+
|
|
154
|
+
Create custom toast programmatically:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { useToast } from '@djangocfg/ui';
|
|
158
|
+
import { createValidationErrorToast } from '@djangocfg/layouts/validation';
|
|
159
|
+
|
|
160
|
+
function MyComponent() {
|
|
161
|
+
const { toast } = useToast();
|
|
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`
|
|
193
|
+
|
|
194
|
+
Main provider component for validation error tracking.
|
|
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;
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### `useValidationErrors()`
|
|
219
|
+
|
|
220
|
+
Hook to access validation error state.
|
|
221
|
+
|
|
222
|
+
**Returns:**
|
|
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
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
import { ValidationErrorProvider } from '@djangocfg/layouts/validation';
|
|
341
|
+
|
|
342
|
+
function App() {
|
|
343
|
+
return (
|
|
344
|
+
<ValidationErrorProvider>
|
|
345
|
+
<YourApp />
|
|
346
|
+
</ValidationErrorProvider>
|
|
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
|
+
},
|
|
363
|
+
}}
|
|
364
|
+
>
|
|
365
|
+
{children}
|
|
366
|
+
</ValidationErrorProvider>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Example 3: Manual Toast Trigger
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
import { useToast } from '@djangocfg/ui';
|
|
373
|
+
import { createValidationErrorToast } from '@djangocfg/layouts/validation';
|
|
374
|
+
|
|
375
|
+
function MyForm() {
|
|
376
|
+
const { toast } = useToast();
|
|
377
|
+
|
|
378
|
+
const handleSubmit = async (data) => {
|
|
379
|
+
try {
|
|
380
|
+
await api.createUser(data);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
if (error instanceof ZodError) {
|
|
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
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
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
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
validation/
|
|
479
|
+
├── index.ts # Public exports
|
|
480
|
+
├── ValidationErrorContext.tsx # Provider & hook
|
|
481
|
+
├── ValidationErrorToast.tsx # Toast utilities & copy button
|
|
482
|
+
└── README.md # This file
|
|
483
|
+
```
|
|
484
|
+
|
|
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)
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Copy as cURL Feature
|
|
497
|
+
|
|
498
|
+
### What Gets Copied
|
|
499
|
+
|
|
500
|
+
When you click **🔄 Copy cURL**, a ready-to-use cURL command is generated:
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
curl 'http://localhost:8000/api/proxies/proxies/?page=1&page_size=100' \
|
|
504
|
+
-H 'Accept: */*' \
|
|
505
|
+
-H 'Content-Type: application/json' \
|
|
506
|
+
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
The generator automatically:
|
|
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
|
|
523
|
+
|
|
524
|
+
You can also generate cURL commands programmatically:
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
import { generateCurl, copyCurlToClipboard } from '@djangocfg/layouts/validation';
|
|
528
|
+
|
|
529
|
+
// Generate cURL
|
|
530
|
+
const curl = generateCurl({
|
|
531
|
+
method: 'POST',
|
|
532
|
+
path: '/api/users/',
|
|
533
|
+
token: 'your-token',
|
|
534
|
+
body: { name: 'John' },
|
|
535
|
+
headers: { 'X-Custom': 'value' },
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// Copy to clipboard
|
|
539
|
+
await copyCurlToClipboard(curl);
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### API Reference - cURL
|
|
543
|
+
|
|
544
|
+
#### `generateCurl(options: CurlOptions): string`
|
|
545
|
+
|
|
546
|
+
**Options:**
|
|
547
|
+
```typescript
|
|
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
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
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
|
+
---
|
|
571
|
+
|
|
572
|
+
## Changelog
|
|
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
|