@djangocfg/centrifugo 1.0.1 → 1.0.2
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 +345 -34
- package/package.json +6 -4
- package/src/config.ts +1 -1
- package/src/core/client/CentrifugoRPCClient.ts +281 -0
- package/src/core/client/index.ts +5 -0
- package/src/core/index.ts +15 -0
- package/src/core/logger/LogsStore.ts +101 -0
- package/src/core/logger/createLogger.ts +79 -0
- package/src/core/logger/index.ts +9 -0
- package/src/core/types/index.ts +68 -0
- package/src/debug/ConnectionTab/ConnectionTab.tsx +160 -0
- package/src/debug/ConnectionTab/index.ts +5 -0
- package/src/debug/DebugPanel/DebugPanel.tsx +102 -0
- package/src/debug/DebugPanel/index.ts +5 -0
- package/src/debug/LogsTab/LogsTab.tsx +236 -0
- package/src/debug/LogsTab/index.ts +5 -0
- package/src/debug/SubscriptionsTab/SubscriptionsTab.tsx +135 -0
- package/src/debug/SubscriptionsTab/index.ts +5 -0
- package/src/debug/index.ts +11 -0
- package/src/hooks/index.ts +2 -5
- package/src/hooks/useSubscription.ts +66 -65
- package/src/index.ts +94 -13
- package/src/providers/CentrifugoProvider/CentrifugoProvider.tsx +381 -0
- package/src/providers/CentrifugoProvider/index.ts +6 -0
- package/src/providers/LogsProvider/LogsProvider.tsx +107 -0
- package/src/providers/LogsProvider/index.ts +6 -0
- package/src/providers/index.ts +9 -0
- package/API_GENERATOR.md +0 -253
- package/src/components/CentrifugoDebug.tsx +0 -182
- package/src/components/index.ts +0 -5
- package/src/context/CentrifugoProvider.tsx +0 -228
- package/src/context/index.ts +0 -5
- package/src/hooks/useLogger.ts +0 -69
- package/src/types/index.ts +0 -45
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs Provider
|
|
3
|
+
*
|
|
4
|
+
* Provides access to accumulated logs via React Context.
|
|
5
|
+
* Wraps LogsStore and exposes logs + controls.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use client';
|
|
9
|
+
|
|
10
|
+
import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react';
|
|
11
|
+
import type { LogEntry, LogLevel } from '../../core/types';
|
|
12
|
+
import { getGlobalLogsStore } from '../../core/logger';
|
|
13
|
+
|
|
14
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
15
|
+
// Context
|
|
16
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
export interface LogsContextValue {
|
|
19
|
+
logs: LogEntry[];
|
|
20
|
+
filteredLogs: LogEntry[];
|
|
21
|
+
filter: LogsFilter;
|
|
22
|
+
setFilter: (filter: Partial<LogsFilter>) => void;
|
|
23
|
+
clearLogs: () => void;
|
|
24
|
+
count: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface LogsFilter {
|
|
28
|
+
level?: LogLevel;
|
|
29
|
+
source?: LogEntry['source'];
|
|
30
|
+
search?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const LogsContext = createContext<LogsContextValue | undefined>(undefined);
|
|
34
|
+
|
|
35
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
36
|
+
// Provider
|
|
37
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
export interface LogsProviderProps {
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function LogsProvider({ children }: LogsProviderProps) {
|
|
44
|
+
const [logs, setLogs] = useState<LogEntry[]>([]);
|
|
45
|
+
const [filter, setFilterState] = useState<LogsFilter>({});
|
|
46
|
+
|
|
47
|
+
const logsStore = getGlobalLogsStore();
|
|
48
|
+
|
|
49
|
+
// Subscribe to log changes
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
// Initial load
|
|
52
|
+
setLogs(logsStore.getAll());
|
|
53
|
+
|
|
54
|
+
// Subscribe to updates
|
|
55
|
+
const unsubscribe = logsStore.subscribe((updatedLogs) => {
|
|
56
|
+
setLogs(updatedLogs);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return unsubscribe;
|
|
60
|
+
}, [logsStore]);
|
|
61
|
+
|
|
62
|
+
// Filter logs
|
|
63
|
+
const filteredLogs = logs.filter((log) => {
|
|
64
|
+
if (filter.level && log.level !== filter.level) return false;
|
|
65
|
+
if (filter.source && log.source !== filter.source) return false;
|
|
66
|
+
if (filter.search) {
|
|
67
|
+
const searchLower = filter.search.toLowerCase();
|
|
68
|
+
return log.message.toLowerCase().includes(searchLower);
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Set filter (merge with existing)
|
|
74
|
+
const setFilter = useCallback((partialFilter: Partial<LogsFilter>) => {
|
|
75
|
+
setFilterState((prev) => ({ ...prev, ...partialFilter }));
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
78
|
+
// Clear all logs
|
|
79
|
+
const clearLogs = useCallback(() => {
|
|
80
|
+
logsStore.clear();
|
|
81
|
+
}, [logsStore]);
|
|
82
|
+
|
|
83
|
+
const value: LogsContextValue = {
|
|
84
|
+
logs,
|
|
85
|
+
filteredLogs,
|
|
86
|
+
filter,
|
|
87
|
+
setFilter,
|
|
88
|
+
clearLogs,
|
|
89
|
+
count: logs.length,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return <LogsContext.Provider value={value}>{children}</LogsContext.Provider>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
96
|
+
// Hook
|
|
97
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
export function useLogs(): LogsContextValue {
|
|
100
|
+
const context = useContext(LogsContext);
|
|
101
|
+
|
|
102
|
+
if (context === undefined) {
|
|
103
|
+
throw new Error('useLogs must be used within a LogsProvider');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return context;
|
|
107
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Providers Module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { CentrifugoProvider, useCentrifugo } from './CentrifugoProvider';
|
|
6
|
+
export type { CentrifugoContextValue, CentrifugoProviderProps } from './CentrifugoProvider';
|
|
7
|
+
|
|
8
|
+
export { LogsProvider, useLogs } from './LogsProvider';
|
|
9
|
+
export type { LogsContextValue, LogsFilter, LogsProviderProps } from './LogsProvider';
|
package/API_GENERATOR.md
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
# Centrifugo Client Generator
|
|
2
|
-
|
|
3
|
-
Documentation for generating Centrifugo WebSocket RPC clients from gRPC services and Django configuration.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The Centrifugo client generator creates typed WebSocket RPC clients from:
|
|
8
|
-
- **gRPC Services**: Protocol buffer definitions and service implementations
|
|
9
|
-
- **Django Config**: Configuration schema from `config.py`
|
|
10
|
-
|
|
11
|
-
This enables full-stack type safety and auto-completion for WebSocket RPC communication.
|
|
12
|
-
|
|
13
|
-
## Paths Reference
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
$PACKAGES = ../packages (monorepo packages root)
|
|
17
|
-
$ADMIN = ../apps/admin (admin app root)
|
|
18
|
-
$DJANGO = ../../../../solution/projects/django (django project root)
|
|
19
|
-
$DJANGO_CFG = ../../../../solution/projects/django_cfg (django_cfg package)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Quick Start
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
# From admin app root
|
|
26
|
-
cd $ADMIN && make centrifugo
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
This will:
|
|
30
|
-
1. Generate clients (TypeScript, Python, Go) in `$DJANGO/openapi/centrifugo/`
|
|
31
|
-
2. Copy TypeScript client to `$ADMIN/src/centrifugo/generated/`
|
|
32
|
-
|
|
33
|
-
## Generator Architecture
|
|
34
|
-
|
|
35
|
-
### 1. Management Command
|
|
36
|
-
|
|
37
|
-
**Location**: `$DJANGO/core/management/commands/generate_centrifugo.py`
|
|
38
|
-
|
|
39
|
-
This is the main entry point that orchestrates the generation process.
|
|
40
|
-
|
|
41
|
-
```python
|
|
42
|
-
# Usage
|
|
43
|
-
python manage.py generate_centrifugo
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### 2. Codegen Logic
|
|
47
|
-
|
|
48
|
-
**Location**: `$DJANGO_CFG/apps/integrations/centrifugo/codegen/`
|
|
49
|
-
|
|
50
|
-
The generator has modular architecture:
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
codegen/
|
|
54
|
-
├── management/commands/
|
|
55
|
-
│ └── generate_centrifugo_clients.py # Core generator command
|
|
56
|
-
├── generators/
|
|
57
|
-
│ ├── typescript_thin/ # TypeScript client generator
|
|
58
|
-
│ │ ├── generator.py
|
|
59
|
-
│ │ └── templates/ # Jinja2 templates
|
|
60
|
-
│ ├── python/ # Python client generator
|
|
61
|
-
│ └── go/ # Go client generator
|
|
62
|
-
└── utils/ # Shared utilities
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### 3. Templates
|
|
66
|
-
|
|
67
|
-
Client generation uses Jinja2 templates located in:
|
|
68
|
-
- `$DJANGO_CFG/apps/integrations/centrifugo/codegen/generators/typescript_thin/templates/`
|
|
69
|
-
|
|
70
|
-
Key templates:
|
|
71
|
-
- `client.ts.j2` - RPC method wrappers
|
|
72
|
-
- `rpc-client.ts.j2` - Base Centrifugo client with connection logic
|
|
73
|
-
- `types.ts.j2` - TypeScript type definitions
|
|
74
|
-
|
|
75
|
-
## Source Data
|
|
76
|
-
|
|
77
|
-
### gRPC Services
|
|
78
|
-
|
|
79
|
-
**Location**: `$DJANGO/apps/*/grpc_services`
|
|
80
|
-
|
|
81
|
-
The generator scans all Django apps for gRPC service definitions:
|
|
82
|
-
- `.proto` files
|
|
83
|
-
- Service implementations
|
|
84
|
-
- Method signatures
|
|
85
|
-
|
|
86
|
-
### Django Config
|
|
87
|
-
|
|
88
|
-
**Location**: `$DJANGO/api/config.py`
|
|
89
|
-
|
|
90
|
-
Configuration schema is extracted from:
|
|
91
|
-
```python
|
|
92
|
-
class ConfigView(APIView):
|
|
93
|
-
@action(detail=False, methods=['get'])
|
|
94
|
-
def config(self, request):
|
|
95
|
-
return Response({
|
|
96
|
-
'centrifugo': {
|
|
97
|
-
'enabled': settings.CENTRIFUGO_ENABLED,
|
|
98
|
-
'url': settings.CENTRIFUGO_URL,
|
|
99
|
-
# ...
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Generated Outputs
|
|
105
|
-
|
|
106
|
-
### TypeScript Client
|
|
107
|
-
|
|
108
|
-
**Output**: `$DJANGO/openapi/centrifugo/typescript/`
|
|
109
|
-
|
|
110
|
-
Generated files:
|
|
111
|
-
- `client.ts` - High-level RPC method wrappers
|
|
112
|
-
- `rpc-client.ts` - Low-level Centrifugo client
|
|
113
|
-
- `types.ts` - TypeScript interfaces
|
|
114
|
-
|
|
115
|
-
**Copied to**: `$ADMIN/src/centrifugo/generated/`
|
|
116
|
-
|
|
117
|
-
### Python Client
|
|
118
|
-
|
|
119
|
-
**Output**: `$DJANGO/openapi/centrifugo/python/`
|
|
120
|
-
|
|
121
|
-
### Go Client
|
|
122
|
-
|
|
123
|
-
**Output**: `$DJANGO/openapi/centrifugo/go/`
|
|
124
|
-
|
|
125
|
-
## Modifying the Generator
|
|
126
|
-
|
|
127
|
-
The codegen logic is in `$DJANGO_CFG` which is auto-linked to Django. Changes are immediately available:
|
|
128
|
-
|
|
129
|
-
1. Edit generator code or templates in `$DJANGO_CFG/apps/integrations/centrifugo/codegen/`
|
|
130
|
-
2. Re-run generation: `cd $ADMIN && make centrifugo`
|
|
131
|
-
3. Verify generated output
|
|
132
|
-
|
|
133
|
-
### Example: Modify TypeScript Template
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
# Edit base client template
|
|
137
|
-
vim $DJANGO_CFG/apps/integrations/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2
|
|
138
|
-
|
|
139
|
-
# Regenerate
|
|
140
|
-
cd $ADMIN && make centrifugo
|
|
141
|
-
|
|
142
|
-
# Check output
|
|
143
|
-
cat $ADMIN/src/centrifugo/generated/rpc-client.ts
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Integration with Admin App
|
|
147
|
-
|
|
148
|
-
The admin app wraps the generated client with app-specific providers:
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
$ADMIN/src/centrifugo/
|
|
152
|
-
├── generated/ # Auto-generated (DO NOT EDIT)
|
|
153
|
-
│ ├── client.ts
|
|
154
|
-
│ ├── rpc-client.ts
|
|
155
|
-
│ └── types.ts
|
|
156
|
-
├── AppCentrifugoProvider.tsx # App-specific wrapper
|
|
157
|
-
└── index.ts # Re-exports from @djangocfg/centrifugo
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Universal components (context, hooks, debug) are in `@djangocfg/centrifugo` package:
|
|
161
|
-
|
|
162
|
-
```
|
|
163
|
-
$PACKAGES/centrifugo/src/
|
|
164
|
-
├── context/ # React context provider
|
|
165
|
-
├── hooks/ # Custom hooks
|
|
166
|
-
├── components/ # Debug panel, etc.
|
|
167
|
-
├── config.ts # Environment config
|
|
168
|
-
└── types.ts # Shared types
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## Development Workflow
|
|
172
|
-
|
|
173
|
-
### 1. Add New gRPC Service
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
# 1. Define .proto file
|
|
177
|
-
vim $DJANGO/apps/myapp/grpc_services/myservice.proto
|
|
178
|
-
|
|
179
|
-
# 2. Implement service
|
|
180
|
-
vim $DJANGO/apps/myapp/grpc_services/myservice.py
|
|
181
|
-
|
|
182
|
-
# 3. Regenerate client
|
|
183
|
-
cd $ADMIN && make centrifugo
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### 2. Use in Frontend
|
|
187
|
-
|
|
188
|
-
```tsx
|
|
189
|
-
import { useCentrifugo } from '@/centrifugo';
|
|
190
|
-
|
|
191
|
-
function MyComponent() {
|
|
192
|
-
const { client, isConnected } = useCentrifugo();
|
|
193
|
-
|
|
194
|
-
const handleCall = async () => {
|
|
195
|
-
// Auto-generated typed method
|
|
196
|
-
const result = await client?.myMethod({ param: 'value' });
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## Troubleshooting
|
|
202
|
-
|
|
203
|
-
### Client Generation Fails
|
|
204
|
-
|
|
205
|
-
1. Check Django apps are properly configured
|
|
206
|
-
2. Verify gRPC services are valid
|
|
207
|
-
3. Check template syntax in `$DJANGO_CFG/apps/integrations/centrifugo/codegen/generators/typescript_thin/templates/`
|
|
208
|
-
|
|
209
|
-
### TypeScript Errors After Generation
|
|
210
|
-
|
|
211
|
-
1. Check generated types in `src/centrifugo/generated/types.ts`
|
|
212
|
-
2. Verify imports match package structure
|
|
213
|
-
3. Run type check: `pnpm tsc --noEmit`
|
|
214
|
-
|
|
215
|
-
### Connection Issues
|
|
216
|
-
|
|
217
|
-
Use the debug panel (FAB button in bottom-left corner) to inspect:
|
|
218
|
-
- Connection state
|
|
219
|
-
- Authentication status
|
|
220
|
-
- WebSocket URL
|
|
221
|
-
- Channel subscriptions
|
|
222
|
-
- Error messages
|
|
223
|
-
|
|
224
|
-
## Advanced Configuration
|
|
225
|
-
|
|
226
|
-
### Custom Templates
|
|
227
|
-
|
|
228
|
-
You can customize the generated output by modifying templates:
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
# Location
|
|
232
|
-
$DJANGO_CFG/apps/integrations/centrifugo/codegen/generators/typescript_thin/templates/
|
|
233
|
-
|
|
234
|
-
# Files
|
|
235
|
-
client.ts.j2 # Method wrappers
|
|
236
|
-
rpc-client.ts.j2 # Base client
|
|
237
|
-
types.ts.j2 # Type definitions
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Generator Options
|
|
241
|
-
|
|
242
|
-
The `generate_centrifugo_clients` command supports options:
|
|
243
|
-
|
|
244
|
-
```bash
|
|
245
|
-
python manage.py generate_centrifugo_clients --help
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
## References
|
|
249
|
-
|
|
250
|
-
- **Centrifugo Docs**: https://centrifugal.dev/
|
|
251
|
-
- **Centrifuge-JS**: https://github.com/centrifugal/centrifuge-js
|
|
252
|
-
- **gRPC**: https://grpc.io/
|
|
253
|
-
- **Jinja2**: https://jinja.palletsprojects.com/
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Centrifugo Debug Component
|
|
3
|
-
*
|
|
4
|
-
* Displays detailed Centrifugo connection status and diagnostics
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
'use client';
|
|
8
|
-
|
|
9
|
-
import React from 'react';
|
|
10
|
-
import { useCentrifugo } from '../context';
|
|
11
|
-
import { useAuth } from '@djangocfg/layouts';
|
|
12
|
-
import { Card, CardHeader, CardTitle, CardContent, Badge, Separator, Button, useCopy } from '@djangocfg/ui';
|
|
13
|
-
import { PrettyCode } from '@djangocfg/ui/tools';
|
|
14
|
-
import { Wifi, WifiOff, Radio, X, Copy, RefreshCw } from 'lucide-react';
|
|
15
|
-
import { centrifugoConfig } from '../config';
|
|
16
|
-
|
|
17
|
-
export function CentrifugoDebug() {
|
|
18
|
-
const { isConnected, isConnecting, error, connectionState, baseClient, enabled, reconnect } = useCentrifugo();
|
|
19
|
-
const { isAuthenticated, isLoading: authLoading, user } = useAuth();
|
|
20
|
-
const [isVisible, setIsVisible] = React.useState(true);
|
|
21
|
-
const [isReconnecting, setIsReconnecting] = React.useState(false);
|
|
22
|
-
const { copyToClipboard } = useCopy();
|
|
23
|
-
|
|
24
|
-
const centrifugoToken = user?.centrifugo;
|
|
25
|
-
const hasCentrifugoToken = !!centrifugoToken?.token;
|
|
26
|
-
|
|
27
|
-
const shouldConnect = isAuthenticated && !authLoading && enabled && hasCentrifugoToken;
|
|
28
|
-
|
|
29
|
-
const debugInfo = React.useMemo(() => ({
|
|
30
|
-
connection: {
|
|
31
|
-
status: connectionState,
|
|
32
|
-
isConnected,
|
|
33
|
-
isConnecting,
|
|
34
|
-
error: error?.message || null,
|
|
35
|
-
},
|
|
36
|
-
auth: {
|
|
37
|
-
isAuthenticated,
|
|
38
|
-
authLoading,
|
|
39
|
-
userId: user?.id,
|
|
40
|
-
},
|
|
41
|
-
config: {
|
|
42
|
-
centrifugoEnabled: enabled,
|
|
43
|
-
hasCentrifugoToken,
|
|
44
|
-
},
|
|
45
|
-
websocket: {
|
|
46
|
-
url: centrifugoToken?.centrifugo_url || null,
|
|
47
|
-
channels: centrifugoToken?.channels || [],
|
|
48
|
-
activeSubscriptions: baseClient?.getAllSubscriptions?.() || [],
|
|
49
|
-
},
|
|
50
|
-
autoConnect: {
|
|
51
|
-
shouldConnect,
|
|
52
|
-
reasons: {
|
|
53
|
-
authenticated: isAuthenticated,
|
|
54
|
-
authLoading: !authLoading,
|
|
55
|
-
centrifugoEnabled: enabled,
|
|
56
|
-
hasToken: hasCentrifugoToken,
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
}), [connectionState, isConnected, isConnecting, error, isAuthenticated, authLoading, user?.id, enabled, hasCentrifugoToken, centrifugoToken, baseClient, shouldConnect]);
|
|
60
|
-
|
|
61
|
-
const copyDebugInfo = () => {
|
|
62
|
-
copyToClipboard(JSON.stringify(debugInfo, null, 2), 'Debug info copied to clipboard');
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const handleReconnect = async () => {
|
|
66
|
-
setIsReconnecting(true);
|
|
67
|
-
try {
|
|
68
|
-
await reconnect();
|
|
69
|
-
} finally {
|
|
70
|
-
setTimeout(() => setIsReconnecting(false), 1000);
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Only show in development mode and not in static builds
|
|
75
|
-
if (!centrifugoConfig.showDebugPanel) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<>
|
|
81
|
-
{/* FAB Button (always visible) */}
|
|
82
|
-
<button
|
|
83
|
-
onClick={() => setIsVisible(!isVisible)}
|
|
84
|
-
className="rounded-full bg-primary text-primary-foreground shadow-lg hover:shadow-xl transition-all duration-200 flex items-center justify-center"
|
|
85
|
-
style={{ position: 'fixed', bottom: '1rem', left: '1rem', width: '56px', height: '56px', zIndex: 9999 }}
|
|
86
|
-
title="Toggle Centrifugo Debug Panel"
|
|
87
|
-
>
|
|
88
|
-
{isConnected ? (
|
|
89
|
-
<Wifi style={{ width: '24px', height: '24px' }} />
|
|
90
|
-
) : (
|
|
91
|
-
<WifiOff style={{ width: '24px', height: '24px' }} />
|
|
92
|
-
)}
|
|
93
|
-
</button>
|
|
94
|
-
|
|
95
|
-
{/* Debug Panel */}
|
|
96
|
-
{isVisible && (
|
|
97
|
-
<div style={{ position: 'fixed', bottom: '5rem', left: '1rem', width: '420px', zIndex: 9999 }}>
|
|
98
|
-
<Card className="shadow-lg">
|
|
99
|
-
<CardHeader className="pb-3">
|
|
100
|
-
<div className="flex items-center justify-between">
|
|
101
|
-
<div className="flex items-center gap-2">
|
|
102
|
-
{isConnected ? (
|
|
103
|
-
<Wifi className="text-green-600 dark:text-green-500" style={{ width: '16px', height: '16px' }} />
|
|
104
|
-
) : (
|
|
105
|
-
<WifiOff className="text-red-600 dark:text-red-500" style={{ width: '16px', height: '16px' }} />
|
|
106
|
-
)}
|
|
107
|
-
<CardTitle className="text-base">Centrifugo Debug</CardTitle>
|
|
108
|
-
</div>
|
|
109
|
-
<div className="flex items-center gap-1">
|
|
110
|
-
<Button
|
|
111
|
-
variant="ghost"
|
|
112
|
-
size="sm"
|
|
113
|
-
onClick={handleReconnect}
|
|
114
|
-
disabled={isReconnecting || isConnecting}
|
|
115
|
-
className="px-2 py-1"
|
|
116
|
-
title="Reconnect"
|
|
117
|
-
>
|
|
118
|
-
<RefreshCw
|
|
119
|
-
style={{ width: '14px', height: '14px' }}
|
|
120
|
-
className={isReconnecting ? 'animate-spin' : ''}
|
|
121
|
-
/>
|
|
122
|
-
</Button>
|
|
123
|
-
<Button
|
|
124
|
-
variant="ghost"
|
|
125
|
-
size="sm"
|
|
126
|
-
onClick={copyDebugInfo}
|
|
127
|
-
className="px-2 py-1"
|
|
128
|
-
title="Copy debug info"
|
|
129
|
-
>
|
|
130
|
-
<Copy style={{ width: '14px', height: '14px' }} />
|
|
131
|
-
</Button>
|
|
132
|
-
<Button
|
|
133
|
-
variant="ghost"
|
|
134
|
-
size="sm"
|
|
135
|
-
onClick={() => setIsVisible(false)}
|
|
136
|
-
className="px-2 py-1"
|
|
137
|
-
>
|
|
138
|
-
<X style={{ width: '14px', height: '14px' }} />
|
|
139
|
-
</Button>
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
</CardHeader>
|
|
143
|
-
|
|
144
|
-
<CardContent className="space-y-3">
|
|
145
|
-
{/* Connection Status Badge */}
|
|
146
|
-
<div className="flex items-center justify-between">
|
|
147
|
-
<span className="text-sm font-medium">Status:</span>
|
|
148
|
-
<Badge variant={isConnected ? 'default' : isConnecting ? 'secondary' : 'destructive'}>
|
|
149
|
-
{connectionState.toUpperCase()}
|
|
150
|
-
</Badge>
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
{/* Auto-Connect Decision */}
|
|
154
|
-
<div className="flex items-center justify-between">
|
|
155
|
-
<span className="text-sm font-medium">Should Connect:</span>
|
|
156
|
-
<Badge variant={shouldConnect ? 'default' : 'outline'}>
|
|
157
|
-
{shouldConnect ? 'YES' : 'NO'}
|
|
158
|
-
</Badge>
|
|
159
|
-
</div>
|
|
160
|
-
|
|
161
|
-
<Separator />
|
|
162
|
-
|
|
163
|
-
{/* JSON Debug Output */}
|
|
164
|
-
<div className="space-y-2">
|
|
165
|
-
<div className="flex items-center gap-2">
|
|
166
|
-
<Radio className="text-muted-foreground" style={{ width: '14px', height: '14px' }} />
|
|
167
|
-
<span className="text-sm font-medium">Debug State:</span>
|
|
168
|
-
</div>
|
|
169
|
-
<div className="max-h-[300px] overflow-y-auto">
|
|
170
|
-
<PrettyCode data={debugInfo} language="json" />
|
|
171
|
-
</div>
|
|
172
|
-
</div>
|
|
173
|
-
</CardContent>
|
|
174
|
-
</Card>
|
|
175
|
-
</div>
|
|
176
|
-
)}
|
|
177
|
-
</>
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Alias for backward compatibility
|
|
182
|
-
export const WSRPCDebug = CentrifugoDebug;
|