django-cfg 1.4.61__py3-none-any.whl → 1.4.63__py3-none-any.whl

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.

Potentially problematic release.


This version of django-cfg might be problematic. Click here for more details.

Files changed (179) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/services/otp_service.py +3 -14
  3. django_cfg/apps/centrifugo/__init__.py +57 -0
  4. django_cfg/apps/centrifugo/admin/__init__.py +13 -0
  5. django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
  6. django_cfg/apps/centrifugo/admin/config.py +82 -0
  7. django_cfg/apps/centrifugo/apps.py +31 -0
  8. django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
  9. django_cfg/apps/centrifugo/codegen/README.md +242 -0
  10. django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
  11. django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
  12. django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
  13. django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
  14. django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
  15. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
  16. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
  17. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
  18. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
  19. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
  20. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
  21. django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
  22. django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
  23. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
  24. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
  25. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
  26. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
  27. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
  28. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
  29. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
  30. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
  31. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
  32. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
  33. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
  34. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
  35. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
  36. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
  37. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
  38. django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
  39. django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
  40. django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
  41. django_cfg/apps/centrifugo/decorators.py +137 -0
  42. django_cfg/apps/centrifugo/management/__init__.py +1 -0
  43. django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
  44. django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
  45. django_cfg/apps/centrifugo/managers/__init__.py +12 -0
  46. django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
  47. django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
  48. django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
  49. django_cfg/apps/centrifugo/models/__init__.py +11 -0
  50. django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
  51. django_cfg/apps/centrifugo/registry.py +106 -0
  52. django_cfg/apps/centrifugo/router.py +125 -0
  53. django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
  54. django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
  55. django_cfg/apps/centrifugo/serializers/channels.py +26 -0
  56. django_cfg/apps/centrifugo/serializers/health.py +17 -0
  57. django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
  58. django_cfg/apps/centrifugo/serializers/stats.py +21 -0
  59. django_cfg/apps/centrifugo/services/__init__.py +12 -0
  60. django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
  61. django_cfg/apps/centrifugo/services/client/client.py +577 -0
  62. django_cfg/apps/centrifugo/services/client/config.py +228 -0
  63. django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
  64. django_cfg/apps/centrifugo/services/config_helper.py +63 -0
  65. django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
  66. django_cfg/apps/centrifugo/services/logging.py +677 -0
  67. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
  68. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
  69. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
  70. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
  71. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
  72. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
  73. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
  74. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
  75. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
  76. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
  77. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
  78. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
  79. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
  80. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
  81. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
  82. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
  83. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
  84. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
  85. django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
  86. django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
  87. django_cfg/apps/centrifugo/urls.py +31 -0
  88. django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
  89. django_cfg/apps/centrifugo/views/__init__.py +15 -0
  90. django_cfg/apps/centrifugo/views/admin_api.py +374 -0
  91. django_cfg/apps/centrifugo/views/dashboard.py +15 -0
  92. django_cfg/apps/centrifugo/views/monitoring.py +286 -0
  93. django_cfg/apps/centrifugo/views/testing_api.py +422 -0
  94. django_cfg/apps/support/utils/support_email_service.py +5 -18
  95. django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
  96. django_cfg/apps/urls.py +5 -5
  97. django_cfg/core/base/config_model.py +4 -44
  98. django_cfg/core/builders/apps_builder.py +2 -2
  99. django_cfg/core/generation/integration_generators/third_party.py +8 -8
  100. django_cfg/core/utils/__init__.py +5 -0
  101. django_cfg/core/utils/url_helpers.py +73 -0
  102. django_cfg/modules/base.py +7 -7
  103. django_cfg/modules/django_client/core/__init__.py +2 -1
  104. django_cfg/modules/django_client/core/config/config.py +8 -0
  105. django_cfg/modules/django_client/core/generator/__init__.py +42 -2
  106. django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
  107. django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
  108. django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
  109. django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
  110. django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
  111. django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
  112. django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
  113. django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
  114. django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
  115. django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
  116. django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
  117. django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
  118. django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
  119. django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
  120. django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
  121. django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
  122. django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
  123. django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
  124. django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
  125. django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
  126. django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
  127. django_cfg/modules/django_client/system/schema_parser.py +5 -1
  128. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
  129. django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
  130. django_cfg/modules/django_unfold/dashboard.py +25 -19
  131. django_cfg/pyproject.toml +1 -1
  132. django_cfg/registry/core.py +2 -0
  133. django_cfg/registry/modules.py +2 -2
  134. django_cfg/static/js/api/centrifugo/client.mjs +164 -0
  135. django_cfg/static/js/api/centrifugo/index.mjs +13 -0
  136. django_cfg/static/js/api/index.mjs +5 -5
  137. django_cfg/static/js/api/types.mjs +89 -26
  138. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/METADATA +1 -1
  139. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/RECORD +142 -68
  140. django_cfg/apps/ipc/README.md +0 -346
  141. django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
  142. django_cfg/apps/ipc/TESTING.md +0 -539
  143. django_cfg/apps/ipc/__init__.py +0 -60
  144. django_cfg/apps/ipc/admin.py +0 -212
  145. django_cfg/apps/ipc/apps.py +0 -28
  146. django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
  147. django_cfg/apps/ipc/migrations/__init__.py +0 -0
  148. django_cfg/apps/ipc/models.py +0 -221
  149. django_cfg/apps/ipc/serializers/__init__.py +0 -29
  150. django_cfg/apps/ipc/serializers/serializers.py +0 -343
  151. django_cfg/apps/ipc/services/__init__.py +0 -7
  152. django_cfg/apps/ipc/services/client/__init__.py +0 -23
  153. django_cfg/apps/ipc/services/client/client.py +0 -621
  154. django_cfg/apps/ipc/services/client/config.py +0 -214
  155. django_cfg/apps/ipc/services/client/exceptions.py +0 -201
  156. django_cfg/apps/ipc/services/logging.py +0 -239
  157. django_cfg/apps/ipc/services/monitor.py +0 -466
  158. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
  159. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
  160. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
  161. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
  162. django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
  163. django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
  164. django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
  165. django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
  166. django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
  167. django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
  168. django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
  169. django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
  170. django_cfg/apps/ipc/urls.py +0 -23
  171. django_cfg/apps/ipc/views/__init__.py +0 -13
  172. django_cfg/apps/ipc/views/dashboard.py +0 -15
  173. django_cfg/apps/ipc/views/monitoring.py +0 -251
  174. django_cfg/apps/ipc/views/testing.py +0 -285
  175. django_cfg/static/js/api/ipc/client.mjs +0 -114
  176. django_cfg/static/js/api/ipc/index.mjs +0 -13
  177. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/WHEEL +0 -0
  178. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/entry_points.txt +0 -0
  179. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/licenses/LICENSE +0 -0
@@ -1,269 +0,0 @@
1
- /**
2
- * Main RPC Dashboard Controller
3
- * Orchestrates all dashboard modules and handles tab navigation
4
- */
5
- import { OverviewModule } from './overview.mjs';
6
- import { TestingModule } from './testing.mjs';
7
-
8
- class RPCDashboard {
9
- constructor() {
10
- this.api = window.ipcAPI;
11
- this.currentTab = 'overview';
12
- this.autoRefresh = true;
13
- this.refreshInterval = null;
14
- this.refreshRate = 5000; // 5 seconds
15
-
16
- // Initialize modules
17
- this.overviewModule = new OverviewModule(this.api, this);
18
- this.testingModule = new TestingModule(this.api, this);
19
- }
20
-
21
- /**
22
- * Initialize dashboard
23
- */
24
- init() {
25
- console.log('🚀 RPC Dashboard initializing...');
26
- this.setupEventListeners();
27
- this.testingModule.init();
28
- this.loadInitialData();
29
- this.startAutoRefresh();
30
- console.log('✅ RPC Dashboard initialized');
31
- }
32
-
33
- /**
34
- * Setup event listeners
35
- */
36
- setupEventListeners() {
37
- // Tab buttons
38
- const tabButtons = document.querySelectorAll('.tab-button');
39
- tabButtons.forEach(button => {
40
- button.addEventListener('click', (e) => {
41
- // Use currentTarget to get the button element, not the clicked child element
42
- const tabName = e.currentTarget.dataset.tab;
43
- this.switchTab(tabName);
44
- });
45
- });
46
-
47
- // Auto-refresh toggle
48
- const autoRefreshToggle = document.getElementById('auto-refresh-toggle');
49
- if (autoRefreshToggle) {
50
- autoRefreshToggle.checked = this.autoRefresh;
51
- autoRefreshToggle.addEventListener('change', (e) => {
52
- this.autoRefresh = e.target.checked;
53
- if (this.autoRefresh) {
54
- this.startAutoRefresh();
55
- } else {
56
- this.stopAutoRefresh();
57
- }
58
- });
59
- }
60
- }
61
-
62
- /**
63
- * Switch tabs
64
- */
65
- switchTab(tabName) {
66
- console.log('Switching to tab:', tabName);
67
-
68
- // Update tab buttons styling
69
- document.querySelectorAll('.tab-button').forEach(btn => {
70
- if (btn.dataset.tab === tabName) {
71
- btn.classList.add('active', 'text-blue-600', 'dark:text-blue-400', 'border-blue-600', 'dark:border-blue-400');
72
- btn.classList.remove('text-gray-600', 'dark:text-gray-400', 'border-transparent');
73
- } else {
74
- btn.classList.remove('active', 'text-blue-600', 'dark:text-blue-400', 'border-blue-600', 'dark:border-blue-400');
75
- btn.classList.add('text-gray-600', 'dark:text-gray-400', 'border-transparent');
76
- }
77
- });
78
-
79
- // Update tab panels
80
- document.querySelectorAll('.tab-panel').forEach(panel => {
81
- panel.classList.add('hidden');
82
- });
83
-
84
- const activePanel = document.getElementById(`${tabName}-tab`);
85
- if (activePanel) {
86
- activePanel.classList.remove('hidden');
87
- }
88
-
89
- this.currentTab = tabName;
90
- this.loadTabData(tabName);
91
- }
92
-
93
- /**
94
- * Load initial data
95
- */
96
- async loadInitialData() {
97
- console.log('Loading initial data...');
98
- await this.loadHealthStatus();
99
- await this.loadTabData(this.currentTab);
100
- }
101
-
102
- /**
103
- * Load data for specific tab
104
- */
105
- async loadTabData(tabName) {
106
- console.log('Loading data for tab:', tabName);
107
-
108
- try {
109
- // Load overview stats for stat cards (always visible)
110
- await this.overviewModule.loadOverviewStats();
111
-
112
- // Load tab-specific data
113
- if (tabName === 'testing') {
114
- // Testing tab doesn't need data loading, it's interactive
115
- } else {
116
- // Overview, requests, notifications, methods tabs
117
- await this.overviewModule.loadData(tabName);
118
- }
119
-
120
- this.updateLastUpdate();
121
-
122
- } catch (error) {
123
- console.error('Error loading tab data:', error);
124
- }
125
- }
126
-
127
- /**
128
- * Load health status
129
- */
130
- async loadHealthStatus() {
131
- try {
132
- const health = await this.api.ipcAdminApiMonitorHealthRetrieve();
133
-
134
- if (health) {
135
- // Update health indicator
136
- const indicator = document.getElementById('health-indicator');
137
- if (indicator) {
138
- const isHealthy = health.redis_connected && health.stream_exists;
139
- indicator.innerHTML = `
140
- <span class="pulse-dot w-2 h-2 ${isHealthy ? 'bg-green-500' : 'bg-red-500'} rounded-full"></span>
141
- <span class="text-gray-700 dark:text-gray-300">${isHealthy ? 'Connected' : 'Disconnected'}</span>
142
- `;
143
- }
144
-
145
- // Update system status section
146
- this.updateSystemStatus(health);
147
- }
148
- } catch (error) {
149
- console.error('Error loading health status:', error);
150
- }
151
- }
152
-
153
- /**
154
- * Update system status section
155
- */
156
- updateSystemStatus(health) {
157
- const statusContainer = document.getElementById('system-status');
158
- if (!statusContainer) return;
159
-
160
- statusContainer.innerHTML = `
161
- <!-- Redis Status -->
162
- <div class="flex items-start gap-3">
163
- <span class="material-icons flex-shrink-0 text-2xl ${health.redis_connected ? 'text-green-500' : 'text-red-500'}">
164
- ${health.redis_connected ? 'check_circle' : 'cancel'}
165
- </span>
166
- <div class="min-w-0">
167
- <p class="text-sm font-medium text-gray-900 dark:text-white">Redis</p>
168
- <p class="text-xs text-gray-600 dark:text-gray-400">
169
- ${health.redis_connected ? 'Connected (DB 2)' : 'Disconnected'}
170
- </p>
171
- </div>
172
- </div>
173
-
174
- <!-- Stream Status -->
175
- <div class="flex items-start gap-3">
176
- <span class="material-icons flex-shrink-0 text-2xl ${health.stream_exists ? 'text-green-500' : 'text-gray-500'}">
177
- ${health.stream_exists ? 'stream' : 'stream_off'}
178
- </span>
179
- <div class="min-w-0">
180
- <p class="text-sm font-medium text-gray-900 dark:text-white">Request Stream</p>
181
- <p class="text-xs text-gray-600 dark:text-gray-400">
182
- ${health.stream_exists ? `${health.stream_length} entries` : 'Not initialized'}
183
- </p>
184
- </div>
185
- </div>
186
-
187
- <!-- Activity Status -->
188
- <div class="flex items-start gap-3">
189
- <span class="material-icons flex-shrink-0 text-2xl ${health.recent_activity ? 'text-green-500' : 'text-yellow-500'}">
190
- ${health.recent_activity ? 'notifications_active' : 'notifications_paused'}
191
- </span>
192
- <div class="min-w-0">
193
- <p class="text-sm font-medium text-gray-900 dark:text-white">Recent Activity</p>
194
- <p class="text-xs text-gray-600 dark:text-gray-400">
195
- ${health.recent_activity ? 'Active (last 5 min)' : 'No recent activity'}
196
- </p>
197
- </div>
198
- </div>
199
- `;
200
- }
201
-
202
- /**
203
- * Update last update timestamp
204
- */
205
- updateLastUpdate() {
206
- const element = document.getElementById('last-update');
207
- if (element) {
208
- const now = new Date();
209
- element.textContent = `Last updated: ${now.toLocaleTimeString()}`;
210
- }
211
- }
212
-
213
- /**
214
- * Start auto-refresh
215
- */
216
- startAutoRefresh() {
217
- if (this.refreshInterval) {
218
- clearInterval(this.refreshInterval);
219
- }
220
-
221
- this.refreshInterval = setInterval(() => {
222
- if (this.autoRefresh) {
223
- this.loadHealthStatus();
224
- this.loadTabData(this.currentTab);
225
- }
226
- }, this.refreshRate);
227
- }
228
-
229
- /**
230
- * Stop auto-refresh
231
- */
232
- stopAutoRefresh() {
233
- if (this.refreshInterval) {
234
- clearInterval(this.refreshInterval);
235
- this.refreshInterval = null;
236
- }
237
- }
238
- }
239
-
240
- /**
241
- * Wait for both DOM and API to be ready
242
- */
243
- async function initializeDashboard() {
244
- console.log('DOM loaded, waiting for IpcAPI...');
245
-
246
- // Wait for API to be available (max 5 seconds)
247
- let attempts = 0;
248
- const maxAttempts = 100; // 100 * 50ms = 5 seconds
249
-
250
- while (!window.ipcAPI && attempts < maxAttempts) {
251
- await new Promise(resolve => setTimeout(resolve, 50));
252
- attempts++;
253
- }
254
-
255
- if (!window.ipcAPI) {
256
- console.error('❌ IpcAPI failed to load after 5 seconds');
257
- return;
258
- }
259
-
260
- console.log('✅ IpcAPI ready, initializing dashboard...');
261
- window.rpcDashboard = new RPCDashboard();
262
- window.rpcDashboard.init();
263
- }
264
-
265
- // Initialize dashboard when DOM is ready
266
- document.addEventListener('DOMContentLoaded', initializeDashboard);
267
-
268
- // Export for debugging
269
- export default RPCDashboard;
@@ -1,259 +0,0 @@
1
- /**
2
- * RPC Overview Dashboard Module
3
- * Handles overview, requests, notifications, and methods tabs
4
- */
5
- export class OverviewModule {
6
- constructor(api, dashboard) {
7
- this.api = api;
8
- this.dashboard = dashboard;
9
- }
10
-
11
- /**
12
- * Load data based on current tab
13
- */
14
- async loadData(tabName) {
15
- switch (tabName) {
16
- case 'overview':
17
- await this.loadOverviewStats();
18
- break;
19
- case 'requests':
20
- await this.loadRecentRequests();
21
- break;
22
- case 'notifications':
23
- await this.loadNotificationStats();
24
- break;
25
- case 'methods':
26
- await this.loadMethodStats();
27
- break;
28
- }
29
- }
30
-
31
- /**
32
- * Load overview statistics
33
- */
34
- async loadOverviewStats() {
35
- try {
36
- const stats = await this.api.ipcAdminApiMonitorOverviewRetrieve();
37
-
38
- if (stats) {
39
- // Update stats cards
40
- this.updateElement('total-requests', stats.total_requests_today || 0);
41
- this.updateElement('active-methods-count', stats.active_methods?.length || 0);
42
- this.updateElement('avg-response-time', (stats.avg_response_time_ms || 0).toFixed(0));
43
- this.updateElement('success-rate', (stats.success_rate || 0).toFixed(1));
44
-
45
- // Update top method (XSS-safe)
46
- if (stats.top_method) {
47
- const topMethodElement = document.getElementById('top-method');
48
- if (topMethodElement) {
49
- const code = document.createElement('code');
50
- code.className = 'bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-blue-600 dark:text-blue-300';
51
- code.textContent = stats.top_method;
52
- topMethodElement.innerHTML = '';
53
- topMethodElement.appendChild(code);
54
- }
55
- }
56
- }
57
- } catch (error) {
58
- console.error('Error loading overview stats:', error);
59
- }
60
- }
61
-
62
- /**
63
- * Load recent RPC requests
64
- */
65
- async loadRecentRequests() {
66
- try {
67
- const data = await this.api.ipcAdminApiMonitorRequestsRetrieve({ count: 50 });
68
-
69
- if (data) {
70
- const requests = data.requests || [];
71
- this.renderRequestsTable(requests);
72
- }
73
- } catch (error) {
74
- console.error('Error loading recent requests:', error);
75
- }
76
- }
77
-
78
- /**
79
- * Render requests table
80
- */
81
- renderRequestsTable(requests) {
82
- const tbody = document.getElementById('requests-table-body');
83
- if (!tbody) return;
84
-
85
- if (requests.length === 0) {
86
- tbody.innerHTML = `
87
- <tr>
88
- <td colspan="4" class="px-4 py-8 text-center text-gray-500 dark:text-gray-400">
89
- No recent requests found
90
- </td>
91
- </tr>
92
- `;
93
- return;
94
- }
95
-
96
- tbody.innerHTML = requests.map(req => `
97
- <tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
98
- <td class="px-4 py-3 text-sm">
99
- ${this.formatTimestamp(req.timestamp)}
100
- </td>
101
- <td class="px-4 py-3">
102
- <code class="text-sm bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">${this.escapeHtml(req.method || 'unknown')}</code>
103
- </td>
104
- <td class="px-4 py-3 text-sm font-mono">
105
- ${this.escapeHtml((req.correlation_id || '').substring(0, 8))}...
106
- </td>
107
- <td class="px-4 py-3 text-sm">
108
- <details class="cursor-pointer">
109
- <summary class="text-blue-600 dark:text-blue-400 hover:underline">View</summary>
110
- <pre class="mt-2 text-xs bg-gray-100 dark:bg-gray-900 p-2 rounded overflow-auto max-h-40">${this.escapeHtml(JSON.stringify(req.params || {}, null, 2))}</pre>
111
- </details>
112
- </td>
113
- </tr>
114
- `).join('');
115
- }
116
-
117
- /**
118
- * Load notification statistics
119
- */
120
- async loadNotificationStats() {
121
- try {
122
- const stats = await this.api.ipcAdminApiMonitorNotificationsRetrieve();
123
-
124
- if (stats) {
125
- this.renderNotificationStats(stats);
126
- }
127
- } catch (error) {
128
- console.error('Error loading notification stats:', error);
129
- }
130
- }
131
-
132
- /**
133
- * Render notification statistics
134
- */
135
- renderNotificationStats(stats) {
136
- const container = document.getElementById('notification-stats-content');
137
- if (!container) return;
138
-
139
- const byType = stats.by_type || {};
140
- const total = stats.total_sent || 0;
141
-
142
- container.innerHTML = `
143
- <div class="space-y-4">
144
- <div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded">
145
- <span>Total Sent</span>
146
- <span class="text-2xl font-bold">${total}</span>
147
- </div>
148
- <div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded">
149
- <span>Delivery Rate</span>
150
- <span class="text-2xl font-bold text-green-600 dark:text-green-400">${stats.delivery_rate || 0}%</span>
151
- </div>
152
- <div>
153
- <h4 class="text-md font-semibold mb-3">By Type</h4>
154
- <div class="space-y-2">
155
- ${Object.entries(byType).map(([type, count]) => `
156
- <div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded">
157
- <span>${this.escapeHtml(type)}</span>
158
- <span class="font-medium">${count}</span>
159
- </div>
160
- `).join('') || '<p class="text-gray-500 dark:text-gray-400">No data available</p>'}
161
- </div>
162
- </div>
163
- ${stats.recent && stats.recent.length > 0 ? `
164
- <div>
165
- <h4 class="text-md font-semibold mb-3">Recent Notifications</h4>
166
- <div class="space-y-2">
167
- ${stats.recent.slice(0, 5).map(notif => `
168
- <div class="p-3 bg-gray-50 dark:bg-gray-700 rounded">
169
- <div class="flex justify-between items-start">
170
- <span class="text-sm">${this.escapeHtml(notif.type || 'unknown')}</span>
171
- <span class="text-xs text-gray-500 dark:text-gray-400">${this.formatTimestamp(notif.timestamp)}</span>
172
- </div>
173
- ${notif.message ? `<p class="text-xs text-gray-600 dark:text-gray-400 mt-1">${this.escapeHtml(notif.message)}</p>` : ''}
174
- </div>
175
- `).join('')}
176
- </div>
177
- </div>
178
- ` : ''}
179
- </div>
180
- `;
181
- }
182
-
183
- /**
184
- * Load method statistics
185
- */
186
- async loadMethodStats() {
187
- try {
188
- const data = await this.api.ipcAdminApiMonitorMethodsRetrieve();
189
-
190
- if (data) {
191
- const methods = data.methods || [];
192
- this.renderMethodsTable(methods);
193
- }
194
- } catch (error) {
195
- console.error('Error loading method stats:', error);
196
- }
197
- }
198
-
199
- /**
200
- * Render methods table
201
- */
202
- renderMethodsTable(methods) {
203
- const tbody = document.getElementById('methods-table-body');
204
- if (!tbody) return;
205
-
206
- if (methods.length === 0) {
207
- tbody.innerHTML = `
208
- <tr>
209
- <td colspan="4" class="px-4 py-8 text-center text-gray-500 dark:text-gray-400">
210
- No method data available
211
- </td>
212
- </tr>
213
- `;
214
- return;
215
- }
216
-
217
- tbody.innerHTML = methods.map(method => `
218
- <tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
219
- <td class="px-4 py-3">
220
- <code class="text-sm bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">${this.escapeHtml(method.method)}</code>
221
- </td>
222
- <td class="px-4 py-3 text-sm font-medium">${method.count}</td>
223
- <td class="px-4 py-3 text-sm">${method.percentage}%</td>
224
- <td class="px-4 py-3 text-sm">${method.avg_time_ms || method.avg_time || 0}ms</td>
225
- </tr>
226
- `).join('');
227
- }
228
-
229
- /**
230
- * Helper: Update element text content
231
- */
232
- updateElement(id, value) {
233
- const element = document.getElementById(id);
234
- if (element) {
235
- element.textContent = value;
236
- }
237
- }
238
-
239
- /**
240
- * Helper: Format ISO timestamp to local time
241
- */
242
- formatTimestamp(isoString) {
243
- try {
244
- const date = new Date(isoString);
245
- return date.toLocaleTimeString();
246
- } catch {
247
- return 'N/A';
248
- }
249
- }
250
-
251
- /**
252
- * Helper: Escape HTML to prevent XSS
253
- */
254
- escapeHtml(unsafe) {
255
- const div = document.createElement('div');
256
- div.textContent = unsafe;
257
- return div.innerHTML;
258
- }
259
- }