@djangocfg/centrifugo 1.0.3 → 1.0.4

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 CHANGED
@@ -1,41 +1,57 @@
1
1
  # @djangocfg/centrifugo
2
2
 
3
- Professional Centrifugo WebSocket client with React integration and comprehensive debugging tools.
3
+ Professional Centrifugo WebSocket client with React integration, composable UI components, and comprehensive monitoring tools.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - 🔌 **Robust WebSocket Connection** - Auto-reconnect, error handling, and connection state management
8
- - 📊 **Advanced Logging System** - Circular buffer with dual output (console + in-memory accumulation)
9
- - 🐛 **Debug UI** - Development-only debug panel with bash-like logs viewer
8
+ - 🔄 **RPC Pattern Support** - Request-response via correlation ID for synchronous-like communication
9
+ - 📊 **Advanced Logging System** - Circular buffer with dual output (consola + in-memory accumulation)
10
+ - 🧩 **Composable UI Components** - Flexible, reusable components for any use case
11
+ - 🐛 **Monitoring Tools** - Real-time connection status, message feed, and subscriptions list
10
12
  - ⚛️ **React Integration** - Context providers and hooks for seamless integration
11
- - 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
13
+ - 🎯 **Type-Safe** - Full TypeScript support with proper Centrifuge types
12
14
  - 🏗️ **Platform-Agnostic Core** - Core modules can be used without React
13
- - 🎨 **Beautiful UI Components** - Pre-built components using shadcn/ui
15
+ - 🎨 **Beautiful UI** - Pre-built components using shadcn/ui
16
+ - 📅 **Moment.js Integration** - Consistent UTC time handling throughout
14
17
 
15
18
  ## Architecture
16
19
 
17
20
  ```
18
21
  src/
19
- ├── core/ # Platform-agnostic (no React dependencies)
20
- │ ├── client/ # CentrifugoRPCClient - WebSocket client
21
- │ ├── logger/ # Logging system with circular buffer
22
- └── types/ # TypeScript type definitions
23
- ├── providers/ # React Context providers
24
- ├── CentrifugoProvider/ # Main connection provider
22
+ ├── core/ # Platform-agnostic (no React dependencies)
23
+ │ ├── client/ # CentrifugoRPCClient - WebSocket client
24
+ │ ├── logger/ # Logging system with circular buffer
25
+ │ ├── createLogger.ts # Logger factory (supports string prefix)
26
+ │ │ └── LogsStore.ts # In-memory logs accumulation
27
+ └── types/ # TypeScript type definitions
28
+ ├── providers/ # React Context providers
29
+ │ ├── CentrifugoProvider/ # Main connection provider (no auto-FAB)
25
30
  │ └── LogsProvider/ # Logs accumulation provider
26
- ├── hooks/ # React hooks
27
- └── useSubscription.ts # Channel subscription hook
28
- └── debug/ # Development-only debug UI (lazy loaded)
29
- ├── DebugPanel/ # Main debug panel with FAB button
30
- ├── ConnectionTab/ # Connection status and controls
31
- ├── LogsTab/ # Bash-like logs viewer
32
- └── SubscriptionsTab/ # Active subscriptions list
31
+ ├── hooks/ # React hooks
32
+ ├── useSubscription.ts # Channel subscription hook
33
+ └── useRPC.ts # RPC request-response hook
34
+ └── components/ # Composable UI components
35
+ ├── ConnectionStatus/ # Connection status display
36
+ ├── ConnectionStatus.tsx # Badge/inline/detailed variants
37
+ └── ConnectionStatusCard.tsx # Card wrapper for dashboards
38
+ ├── MessagesFeed/ # Real-time message feed
39
+ │ ├── MessagesFeed.tsx # Main feed component
40
+ │ ├── MessageFilters.tsx # Filtering controls
41
+ │ └── types.ts # Message types
42
+ ├── SubscriptionsList/ # Active subscriptions list
43
+ │ └── SubscriptionsList.tsx # List with controls
44
+ └── CentrifugoMonitor/ # Main monitoring component
45
+ ├── CentrifugoMonitor.tsx # Composable monitor
46
+ ├── CentrifugoMonitorDialog.tsx # Modal variant
47
+ ├── CentrifugoMonitorFAB.tsx # FAB variant (manual)
48
+ └── CentrifugoMonitorWidget.tsx # Dashboard widget
33
49
  ```
34
50
 
35
51
  ## Installation
36
52
 
37
53
  ```bash
38
- pnpm add @djangocfg/centrifugo
54
+ pnpm add @djangocfg/centrifugo moment
39
55
  ```
40
56
 
41
57
  ## Quick Start
@@ -43,7 +59,7 @@ pnpm add @djangocfg/centrifugo
43
59
  ### 1. Wrap your app with CentrifugoProvider
44
60
 
45
61
  ```tsx
46
- import { CentrifugoProvider, DebugPanel } from '@djangocfg/centrifugo';
62
+ import { CentrifugoProvider } from '@djangocfg/centrifugo';
47
63
 
48
64
  function App() {
49
65
  return (
@@ -52,15 +68,42 @@ function App() {
52
68
  autoConnect={true}
53
69
  >
54
70
  <YourApp />
71
+ </CentrifugoProvider>
72
+ );
73
+ }
74
+ ```
75
+
76
+ ### 2. Add Monitoring FAB (Optional)
77
+
78
+ The FAB is **not** automatically included. You control when and where to show it:
79
+
80
+ ```tsx
81
+ import { CentrifugoProvider, CentrifugoMonitorFAB } from '@djangocfg/centrifugo';
82
+ import { useAuth } from '@djangocfg/layouts';
83
+
84
+ function CentrifugoMonitor() {
85
+ const { isAdminUser } = useAuth();
86
+ const isDevelopment = process.env.NODE_ENV === 'development';
87
+
88
+ // Show FAB only for admins or in development
89
+ if (!isDevelopment && !isAdminUser) {
90
+ return null;
91
+ }
92
+
93
+ return <CentrifugoMonitorFAB variant="full" />;
94
+ }
55
95
 
56
- {/* Debug panel (only shows in development) */}
57
- <DebugPanel />
96
+ function App() {
97
+ return (
98
+ <CentrifugoProvider enabled={true} autoConnect={true}>
99
+ <YourApp />
100
+ <CentrifugoMonitor />
58
101
  </CentrifugoProvider>
59
102
  );
60
103
  }
61
104
  ```
62
105
 
63
- ### 2. Use the connection in your components
106
+ ### 3. Use the connection in your components
64
107
 
65
108
  ```tsx
66
109
  import { useCentrifugo } from '@djangocfg/centrifugo';
@@ -78,7 +121,7 @@ function YourComponent() {
78
121
  }
79
122
  ```
80
123
 
81
- ### 3. Subscribe to channels
124
+ ### 4. Subscribe to channels
82
125
 
83
126
  ```tsx
84
127
  import { useSubscription } from '@djangocfg/centrifugo';
@@ -185,65 +228,305 @@ interface UseSubscriptionOptions<T> {
185
228
  }
186
229
  ```
187
230
 
188
- ### LogsProvider
231
+ ### useRPC()
232
+
233
+ Hook for making RPC calls using correlation ID pattern.
234
+
235
+ **What is RPC Pattern?**
189
236
 
190
- Provider for accessing accumulated logs.
237
+ Centrifugo is pub/sub (fire-and-forget) and doesn't support RPC natively. We implement request-response pattern using **correlation ID** to match requests with responses:
238
+
239
+ ```
240
+ 1. Client generates unique correlation_id
241
+ 2. Client subscribes to personal reply channel (user#{userId})
242
+ 3. Client publishes request with correlation_id to rpc#{method}
243
+ 4. Backend processes and publishes response with same correlation_id
244
+ 5. Client matches response by correlation_id and resolves Promise
245
+ ```
246
+
247
+ **Basic Usage:**
191
248
 
192
249
  ```tsx
193
- const {
194
- logs, // All logs
195
- filteredLogs, // Filtered logs
196
- count, // Total count
197
- filter, // Current filter
198
- setFilter, // Update filter
199
- clearLogs, // Clear all logs
200
- } = useLogs();
250
+ import { useRPC } from '@djangocfg/centrifugo';
251
+
252
+ function MyComponent() {
253
+ const { call, isLoading, error } = useRPC();
254
+
255
+ const handleGetStats = async () => {
256
+ try {
257
+ const result = await call('tasks.get_stats', { bot_id: '123' });
258
+ console.log('Stats:', result);
259
+ } catch (error) {
260
+ console.error('RPC failed:', error);
261
+ }
262
+ };
263
+
264
+ return (
265
+ <button onClick={handleGetStats} disabled={isLoading}>
266
+ {isLoading ? 'Loading...' : 'Get Stats'}
267
+ </button>
268
+ );
269
+ }
201
270
  ```
202
271
 
203
- ## Debug Panel
272
+ **With Type Safety:**
204
273
 
205
- The debug panel is a development-only UI that provides:
274
+ ```tsx
275
+ interface GetStatsRequest {
276
+ bot_id: string;
277
+ }
206
278
 
207
- 1. **Connection Tab** - View connection status, uptime, and controls
208
- 2. **Logs Tab** - Bash-like logs viewer with:
209
- - Filter by level (debug/info/success/warning/error)
210
- - Filter by source (client/provider/subscription/system)
211
- - Search functionality with debounce
212
- - Auto-scroll toggle
213
- - Expandable JSON data with syntax highlighting
214
- 3. **Subscriptions Tab** - View and manage active subscriptions
279
+ interface GetStatsResponse {
280
+ total_tasks: number;
281
+ completed: number;
282
+ failed: number;
283
+ }
284
+
285
+ const { call } = useRPC();
286
+
287
+ const result = await call<GetStatsRequest, GetStatsResponse>(
288
+ 'tasks.get_stats',
289
+ { bot_id: '123' }
290
+ );
291
+
292
+ console.log(result.total_tasks); // Type-safe!
293
+ ```
294
+
295
+ **With Custom Options:**
215
296
 
216
- **Usage:**
217
297
  ```tsx
218
- import { DebugPanel } from '@djangocfg/centrifugo';
298
+ const { call, isLoading, error, reset } = useRPC({
299
+ timeout: 30000, // 30 seconds
300
+ onError: (error) => {
301
+ toast.error(`RPC failed: ${error.message}`);
302
+ },
303
+ });
219
304
 
220
- function App() {
305
+ // Reset state
306
+ reset();
307
+ ```
308
+
309
+ **Options:**
310
+ ```typescript
311
+ interface UseRPCOptions {
312
+ timeout?: number; // Default: 10000ms
313
+ replyChannel?: string; // Default: user#{userId}
314
+ onError?: (error: Error) => void;
315
+ }
316
+
317
+ interface UseRPCResult {
318
+ call: <TRequest, TResponse>(
319
+ method: string,
320
+ params: TRequest,
321
+ options?: UseRPCOptions
322
+ ) => Promise<TResponse>;
323
+ isLoading: boolean;
324
+ error: Error | null;
325
+ reset: () => void;
326
+ }
327
+ ```
328
+
329
+ **Backend Implementation:**
330
+
331
+ The backend should subscribe to `rpc#{method}` channels and publish responses:
332
+
333
+ ```python
334
+ # Django backend example
335
+ from django_cfg.apps.integrations.centrifugo import get_centrifugo_publisher
336
+
337
+ publisher = get_centrifugo_publisher()
338
+
339
+ # Listen to RPC requests (via Centrifugo subscription)
340
+ async def handle_rpc_request(data):
341
+ correlation_id = data['correlation_id']
342
+ method = data['method']
343
+ params = data['params']
344
+ reply_to = data['reply_to']
345
+
346
+ try:
347
+ # Process request
348
+ result = await process_task_stats(params['bot_id'])
349
+
350
+ # Send response
351
+ await publisher.publish(
352
+ channel=reply_to,
353
+ data={
354
+ 'correlation_id': correlation_id,
355
+ 'result': result,
356
+ }
357
+ )
358
+ except Exception as e:
359
+ # Send error response
360
+ await publisher.publish(
361
+ channel=reply_to,
362
+ data={
363
+ 'correlation_id': correlation_id,
364
+ 'error': {'message': str(e)},
365
+ }
366
+ )
367
+ ```
368
+
369
+ ## UI Components
370
+
371
+ All components are composable and can be used independently or together.
372
+
373
+ ### ConnectionStatus
374
+
375
+ Display connection status in various formats.
376
+
377
+ **Variants:**
378
+ - `badge` - Compact badge with status indicator
379
+ - `inline` - Inline text with icon
380
+ - `detailed` - Detailed view with uptime and subscriptions
381
+
382
+ ```tsx
383
+ import { ConnectionStatus } from '@djangocfg/centrifugo';
384
+
385
+ // Badge variant
386
+ <ConnectionStatus variant="badge" />
387
+
388
+ // Detailed variant with uptime and subscriptions
389
+ <ConnectionStatus
390
+ variant="detailed"
391
+ showUptime={true}
392
+ showSubscriptions={true}
393
+ />
394
+ ```
395
+
396
+ **ConnectionStatusCard** - Card wrapper for dashboards:
397
+
398
+ ```tsx
399
+ import { ConnectionStatusCard } from '@djangocfg/centrifugo';
400
+
401
+ <ConnectionStatusCard />
402
+ ```
403
+
404
+ ### MessagesFeed
405
+
406
+ Real-time feed of Centrifugo messages with filtering and export.
407
+
408
+ ```tsx
409
+ import { MessagesFeed } from '@djangocfg/centrifugo';
410
+
411
+ <MessagesFeed
412
+ maxMessages={100}
413
+ showFilters={true}
414
+ showControls={true}
415
+ autoScroll={true}
416
+ onMessageClick={(msg) => console.log(msg)}
417
+ />
418
+ ```
419
+
420
+ **Features:**
421
+ - Filter by type, level, channel
422
+ - Search functionality
423
+ - Pause/play auto-scroll
424
+ - Download messages as JSON
425
+ - Clear messages
426
+
427
+ ### SubscriptionsList
428
+
429
+ List of active subscriptions with management controls.
430
+
431
+ ```tsx
432
+ import { SubscriptionsList } from '@djangocfg/centrifugo';
433
+
434
+ <SubscriptionsList
435
+ showControls={true}
436
+ onSubscriptionClick={(channel) => console.log(channel)}
437
+ />
438
+ ```
439
+
440
+ **Features:**
441
+ - Real-time subscription updates
442
+ - Unsubscribe from channels
443
+ - Click to view channel details
444
+
445
+ ### CentrifugoMonitor
446
+
447
+ Main monitoring component with multiple variants.
448
+
449
+ **Basic Usage:**
450
+
451
+ ```tsx
452
+ import { CentrifugoMonitor } from '@djangocfg/centrifugo';
453
+
454
+ // Embedded in a page
455
+ <CentrifugoMonitor defaultTab="messages" />
456
+ ```
457
+
458
+ **Dialog Variant:**
459
+
460
+ ```tsx
461
+ import { CentrifugoMonitorDialog } from '@djangocfg/centrifugo';
462
+
463
+ function MyComponent() {
464
+ const [open, setOpen] = useState(false);
465
+
221
466
  return (
222
467
  <>
223
- <YourApp />
224
- <DebugPanel />
468
+ <button onClick={() => setOpen(true)}>Open Monitor</button>
469
+ <CentrifugoMonitorDialog
470
+ open={open}
471
+ onOpenChange={setOpen}
472
+ defaultTab="status"
473
+ />
225
474
  </>
226
475
  );
227
476
  }
228
477
  ```
229
478
 
230
- The panel only renders in development mode (`NODE_ENV === 'development'`). It appears as a floating action button (FAB) in the bottom-left corner.
479
+ **FAB Variant:**
480
+
481
+ ```tsx
482
+ import { CentrifugoMonitorFAB } from '@djangocfg/centrifugo';
483
+
484
+ // Full variant with all tabs
485
+ <CentrifugoMonitorFAB variant="full" />
486
+
487
+ // Compact variant (status only)
488
+ <CentrifugoMonitorFAB variant="compact" />
489
+ ```
490
+
491
+ **Widget Variant (for Dashboards):**
492
+
493
+ ```tsx
494
+ import { CentrifugoMonitorWidget } from '@djangocfg/centrifugo';
495
+
496
+ <CentrifugoMonitorWidget defaultTab="subscriptions" />
497
+ ```
498
+
499
+ **Props:**
500
+ ```typescript
501
+ interface CentrifugoMonitorProps {
502
+ defaultTab?: 'status' | 'messages' | 'subscriptions';
503
+ className?: string;
504
+ }
505
+ ```
231
506
 
232
507
  ## Logging System
233
508
 
234
509
  The package includes a sophisticated logging system with:
235
510
 
236
511
  - **Circular Buffer** - Stores up to 500 logs (configurable)
237
- - **Dual Output** - Console (dev only) + in-memory store (always)
512
+ - **Dual Output** - Consola (dev only) + in-memory store (always)
238
513
  - **Structured Logs** - Timestamp, level, source, message, and optional data
239
514
  - **Real-time Updates** - Subscribe to log changes for React updates
515
+ - **Prefixed Output** - Logger name appears as `[YourComponent]` in console
240
516
 
241
517
  **Creating a Logger:**
518
+
242
519
  ```typescript
243
520
  import { createLogger } from '@djangocfg/centrifugo';
244
521
 
522
+ // Simple usage with string prefix
523
+ const logger = createLogger('MyComponent');
524
+
525
+ // Advanced usage with full config
245
526
  const logger = createLogger({
246
- source: 'my-module', // or 'client' | 'provider' | 'subscription' | 'system'
527
+ source: 'client', // 'client' | 'provider' | 'subscription' | 'system'
528
+ tag: 'MyComponent',
529
+ isDevelopment: true,
247
530
  });
248
531
 
249
532
  logger.debug('Debug message', { extra: 'data' });
@@ -254,6 +537,7 @@ logger.error('Error message', error);
254
537
  ```
255
538
 
256
539
  **Accessing Logs:**
540
+
257
541
  ```typescript
258
542
  import { getGlobalLogsStore } from '@djangocfg/centrifugo';
259
543
 
@@ -271,6 +555,39 @@ const unsubscribe = logsStore.subscribe((logs) => {
271
555
  logsStore.clear();
272
556
  ```
273
557
 
558
+ **Using LogsProvider:**
559
+
560
+ ```tsx
561
+ import { useLogs } from '@djangocfg/centrifugo';
562
+
563
+ function CustomLogsView() {
564
+ const { logs, setFilter, clearLogs } = useLogs();
565
+
566
+ return (
567
+ <div>
568
+ <button onClick={() => setFilter({ level: 'error' })}>
569
+ Show Errors Only
570
+ </button>
571
+ <button onClick={() => setFilter({ source: 'client' })}>
572
+ Show Client Logs
573
+ </button>
574
+ <button onClick={() => setFilter({ search: 'WebSocket' })}>
575
+ Search "WebSocket"
576
+ </button>
577
+ <button onClick={clearLogs}>
578
+ Clear All
579
+ </button>
580
+
581
+ <ul>
582
+ {logs.map(log => (
583
+ <li key={log.id}>{log.message}</li>
584
+ ))}
585
+ </ul>
586
+ </div>
587
+ );
588
+ }
589
+ ```
590
+
274
591
  ## Advanced Usage
275
592
 
276
593
  ### Using the Core Client (without React)
@@ -278,41 +595,66 @@ logsStore.clear();
278
595
  ```typescript
279
596
  import { CentrifugoRPCClient, createLogger } from '@djangocfg/centrifugo';
280
597
 
281
- const logger = createLogger({ source: 'client' });
598
+ const logger = createLogger('MyApp');
282
599
  const client = new CentrifugoRPCClient(
283
600
  'ws://localhost:8000/ws',
284
601
  'your-token',
285
602
  'user-id',
286
603
  30000, // timeout
287
- logger
604
+ (entry) => logger.info(entry.message, entry.data)
288
605
  );
289
606
 
290
607
  await client.connect();
291
- await client.subscribe('channel-name');
608
+
609
+ // Subscribe to channel
610
+ const unsubscribe = client.subscribe('channel-name', (data) => {
611
+ console.log('Message:', data);
612
+ });
613
+
614
+ // Get native Centrifuge client for low-level access
615
+ const centrifuge = client.getCentrifuge();
616
+ centrifuge.on('connected', () => console.log('Connected'));
292
617
  ```
293
618
 
294
- ### Custom Log Filters
619
+ ### Custom Dashboard Integration
295
620
 
296
621
  ```tsx
297
- import { useLogs } from '@djangocfg/centrifugo';
622
+ import {
623
+ ConnectionStatusCard,
624
+ MessagesFeed,
625
+ SubscriptionsList,
626
+ } from '@djangocfg/centrifugo';
298
627
 
299
- function CustomLogsView() {
300
- const { logs, setFilter } = useLogs();
628
+ function Dashboard() {
629
+ return (
630
+ <div className="grid grid-cols-3 gap-4">
631
+ <ConnectionStatusCard />
632
+
633
+ <div className="col-span-2">
634
+ <MessagesFeed
635
+ maxMessages={50}
636
+ showFilters={false}
637
+ />
638
+ </div>
639
+
640
+ <div className="col-span-3">
641
+ <SubscriptionsList showControls={true} />
642
+ </div>
643
+ </div>
644
+ );
645
+ }
646
+ ```
647
+
648
+ ### Embedded Monitor in Page
649
+
650
+ ```tsx
651
+ import { CentrifugoMonitor } from '@djangocfg/centrifugo';
301
652
 
653
+ function MonitoringPage() {
302
654
  return (
303
- <div>
304
- <button onClick={() => setFilter({ level: 'error' })}>
305
- Show Errors Only
306
- </button>
307
- <button onClick={() => setFilter({ source: 'client' })}>
308
- Show Client Logs
309
- </button>
310
- <button onClick={() => setFilter({ search: 'WebSocket' })}>
311
- Search "WebSocket"
312
- </button>
313
- <button onClick={() => setFilter({})}>
314
- Clear Filters
315
- </button>
655
+ <div className="container mx-auto p-6">
656
+ <h1>WebSocket Monitoring</h1>
657
+ <CentrifugoMonitor defaultTab="messages" />
316
658
  </div>
317
659
  );
318
660
  }
@@ -347,37 +689,144 @@ import type {
347
689
  // Hooks
348
690
  UseSubscriptionOptions,
349
691
  UseSubscriptionResult,
692
+
693
+ // Components
694
+ ConnectionStatusProps,
695
+ MessagesFeedProps,
696
+ SubscriptionsListProps,
697
+ CentrifugoMonitorProps,
350
698
  } from '@djangocfg/centrifugo';
351
699
  ```
352
700
 
353
- ## Migration from Old Version
701
+ **Proper Centrifuge Types:**
354
702
 
355
- If you're migrating from `src_old`, the main changes are:
703
+ The package now uses proper types from the `centrifuge` library:
356
704
 
357
- 1. **Import paths** - All imports now come from `@djangocfg/centrifugo`
358
- 2. **Provider structure** - `CentrifugoProvider` now wraps `LogsProvider`
359
- 3. **New hooks** - `useSubscription` replaces manual subscription management
360
- 4. **Debug UI** - New `DebugPanel` component replaces old debugging
361
- 5. **Logger API** - New `createLogger` with better structure
705
+ ```typescript
706
+ import type { Subscription, SubscriptionState } from 'centrifuge';
707
+
708
+ // No more 'as any' - fully type-safe!
709
+ const centrifuge = client.getCentrifuge();
710
+ const subs = centrifuge.subscriptions();
711
+
712
+ for (const [channel, sub] of Object.entries(subs)) {
713
+ console.log(channel, sub.state); // SubscriptionState type
714
+ }
715
+ ```
716
+
717
+ ## Best Practices
718
+
719
+ ### 1. Logger Usage
720
+
721
+ Always use the logger instead of `console`:
722
+
723
+ ```typescript
724
+ // ❌ Bad
725
+ console.log('Message');
726
+
727
+ // ✅ Good
728
+ const logger = createLogger('MyComponent');
729
+ logger.info('Message');
730
+ ```
731
+
732
+ ### 2. Date Handling
733
+
734
+ Use `moment` with UTC for all date operations:
735
+
736
+ ```typescript
737
+ import moment from 'moment';
738
+
739
+ // ❌ Bad
740
+ const now = new Date();
741
+ const timestamp = Date.now();
742
+
743
+ // ✅ Good
744
+ const now = moment.utc();
745
+ const timestamp = moment.utc().valueOf();
746
+ const formatted = moment.utc().format('YYYY-MM-DD HH:mm:ss');
747
+ ```
748
+
749
+ ### 3. FAB Control
750
+
751
+ Don't rely on auto-showing FAB. Control it explicitly:
752
+
753
+ ```typescript
754
+ // ✅ Good - Developer has full control
755
+ function App() {
756
+ return (
757
+ <CentrifugoProvider enabled={true}>
758
+ <YourApp />
759
+ {shouldShowMonitor && <CentrifugoMonitorFAB />}
760
+ </CentrifugoProvider>
761
+ );
762
+ }
763
+ ```
764
+
765
+ ### 4. Component Composition
766
+
767
+ Use individual components for custom layouts:
768
+
769
+ ```typescript
770
+ // ✅ Good - Compose as needed
771
+ <div className="monitoring-panel">
772
+ <ConnectionStatus variant="detailed" showUptime />
773
+ <MessagesFeed maxMessages={50} />
774
+ <SubscriptionsList />
775
+ </div>
776
+ ```
777
+
778
+ ## Migration Guide
779
+
780
+ ### From Old DebugPanel
362
781
 
363
782
  **Before:**
364
783
  ```tsx
365
- import { WSRPCContext } from './rpc/WSRPCContext';
784
+ import { DebugPanel } from '@djangocfg/centrifugo';
785
+
786
+ // Auto-shown in development
787
+ <CentrifugoProvider>
788
+ <App />
789
+ </CentrifugoProvider>
366
790
  ```
367
791
 
368
792
  **After:**
369
793
  ```tsx
370
- import { CentrifugoProvider, useCentrifugo } from '@djangocfg/centrifugo';
794
+ import { CentrifugoMonitorFAB } from '@djangocfg/centrifugo';
795
+
796
+ // Manual control
797
+ <CentrifugoProvider>
798
+ <App />
799
+ <CentrifugoMonitorFAB variant="full" />
800
+ </CentrifugoProvider>
801
+ ```
802
+
803
+ ### From date-fns to moment
804
+
805
+ **Before:**
806
+ ```typescript
807
+ import { format } from 'date-fns';
808
+
809
+ const formatted = format(new Date(), 'yyyy-MM-dd HH:mm:ss');
810
+ ```
811
+
812
+ **After:**
813
+ ```typescript
814
+ import moment from 'moment';
815
+
816
+ const formatted = moment.utc().format('YYYY-MM-DD HH:mm:ss');
371
817
  ```
372
818
 
373
819
  ## Development
374
820
 
375
821
  ```bash
822
+ # Install dependencies
823
+ pnpm install
824
+
376
825
  # Build the package
377
826
  pnpm build
378
827
 
379
828
  # Type check
380
- pnpm exec tsc --noEmit
829
+ pnpm check
381
830
 
382
831
  # Run in development mode
383
832
  pnpm dev
@@ -386,9 +835,11 @@ pnpm dev
386
835
  ## Requirements
387
836
 
388
837
  - React 18+
389
- - `@djangocfg/ui` - UI components
838
+ - `@djangocfg/ui` - UI components (shadcn/ui based)
390
839
  - `@djangocfg/layouts` - Layout components
391
840
  - `centrifuge` - WebSocket client library
841
+ - `moment` - Date manipulation library
842
+ - `consola` - Beautiful console logging
392
843
 
393
844
  ## License
394
845