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
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Main Centrifugo Dashboard Controller
3
+ * Orchestrates all dashboard modules and handles tab navigation
4
+ */
5
+ import { OverviewModule } from './overview.mjs';
6
+ import { UsageGuideModule } from './testing.mjs';
7
+ import { LiveChannelsModule } from './live_channels.mjs';
8
+ import { LiveTestingModule } from './live_testing.mjs';
9
+ import { WebSocketModule } from './websocket.mjs';
10
+
11
+ class CentrifugoDashboard {
12
+ constructor() {
13
+ this.api = window.centrifugoAPI;
14
+ this.currentTab = 'overview';
15
+ this.autoRefresh = true;
16
+ this.refreshInterval = null;
17
+ this.refreshRate = 5000; // 5 seconds
18
+
19
+ // Initialize modules
20
+ this.overviewModule = new OverviewModule(this.api, this);
21
+ this.usageGuideModule = new UsageGuideModule(this.api, this);
22
+ this.liveChannelsModule = new LiveChannelsModule(this.api, this);
23
+ this.liveTestingModule = new LiveTestingModule(this.api, this);
24
+ this.websocketModule = new WebSocketModule(this);
25
+ }
26
+
27
+ init() {
28
+ console.log('=� Centrifugo Dashboard initializing...');
29
+ this.setupEventListeners();
30
+ this.usageGuideModule.init();
31
+ this.loadInitialData();
32
+ this.startAutoRefresh();
33
+
34
+ // Initialize WebSocket for real-time updates
35
+ this.websocketModule.init();
36
+ console.log(' Centrifugo Dashboard initialized');
37
+ }
38
+
39
+ isValidTab(tabName) {
40
+ const validTabs = ['overview', 'usage-guide', 'live-channels'];
41
+ return validTabs.includes(tabName);
42
+ }
43
+
44
+ setupEventListeners() {
45
+ // Check URL hash on page load
46
+ const hash = window.location.hash.slice(1); // Remove #
47
+ if (hash && this.isValidTab(hash)) {
48
+ this.currentTab = hash;
49
+ }
50
+
51
+ const tabButtons = document.querySelectorAll('.tab-button');
52
+ tabButtons.forEach(button => {
53
+ button.addEventListener('click', (e) => {
54
+ const tabName = e.currentTarget.dataset.tab;
55
+ this.switchTab(tabName);
56
+ });
57
+ });
58
+
59
+ // Handle browser back/forward buttons
60
+ window.addEventListener('hashchange', () => {
61
+ const hash = window.location.hash.slice(1);
62
+ if (hash && this.isValidTab(hash)) {
63
+ this.switchTab(hash, false); // Don't update hash again
64
+ }
65
+ });
66
+
67
+ const autoRefreshToggle = document.getElementById('auto-refresh-toggle');
68
+ if (autoRefreshToggle) {
69
+ autoRefreshToggle.checked = this.autoRefresh;
70
+ autoRefreshToggle.addEventListener('change', (e) => {
71
+ this.autoRefresh = e.target.checked;
72
+ if (this.autoRefresh) {
73
+ this.startAutoRefresh();
74
+ } else {
75
+ this.stopAutoRefresh();
76
+ }
77
+ });
78
+ }
79
+ }
80
+
81
+ switchTab(tabName, updateHash = true) {
82
+ console.log('Switching to tab:', tabName);
83
+
84
+ // Update URL hash
85
+ if (updateHash) {
86
+ window.history.pushState(null, '', `#${tabName}`);
87
+ }
88
+
89
+ document.querySelectorAll('.tab-button').forEach(btn => {
90
+ if (btn.dataset.tab === tabName) {
91
+ btn.classList.add('active', 'text-purple-600', 'dark:text-purple-400', 'border-purple-600', 'dark:border-purple-400');
92
+ btn.classList.remove('text-gray-600', 'dark:text-gray-400', 'border-transparent');
93
+ } else {
94
+ btn.classList.remove('active', 'text-purple-600', 'dark:text-purple-400', 'border-purple-600', 'dark:border-purple-400');
95
+ btn.classList.add('text-gray-600', 'dark:text-gray-400', 'border-transparent');
96
+ }
97
+ });
98
+
99
+ document.querySelectorAll('.tab-panel').forEach(panel => {
100
+ panel.classList.add('hidden');
101
+ });
102
+
103
+ const activePanel = document.getElementById(tabName + '-tab');
104
+ if (activePanel) {
105
+ activePanel.classList.remove('hidden');
106
+ }
107
+
108
+ this.currentTab = tabName;
109
+ this.loadTabData(tabName);
110
+ }
111
+
112
+ async loadInitialData() {
113
+ console.log('Loading initial data...');
114
+
115
+ // If tab was set from hash, switch to it
116
+ if (this.currentTab !== 'overview') {
117
+ this.switchTab(this.currentTab, false);
118
+ }
119
+
120
+ await this.loadHealthStatus();
121
+ await this.loadTabData(this.currentTab);
122
+ }
123
+
124
+ async loadTabData(tabName) {
125
+ console.log('Loading data for tab:', tabName);
126
+
127
+ try {
128
+ // Always update overview stats (for stat cards at top)
129
+ await this.overviewModule.loadOverviewStats();
130
+
131
+ if (tabName === 'usage-guide') {
132
+ // Usage guide tab doesn't need data loading (static content)
133
+ return;
134
+ } else if (tabName === 'live-channels') {
135
+ // Load live channels from Centrifugo server
136
+ await this.liveChannelsModule.loadLiveChannels();
137
+ } else {
138
+ await this.overviewModule.loadData(tabName);
139
+ }
140
+
141
+ this.updateLastUpdate();
142
+ } catch (error) {
143
+ console.error('Error loading tab data:', error);
144
+ }
145
+ }
146
+
147
+ async loadHealthStatus() {
148
+ try {
149
+ const health = await this.api.centrifugoAdminApiMonitorHealthRetrieve();
150
+
151
+ if (health) {
152
+ const indicator = document.getElementById('health-indicator');
153
+ if (indicator) {
154
+ // Health status is based on whether wrapper_url is configured
155
+ const isHealthy = health.status === 'healthy' && health.wrapper_url;
156
+ const statusColor = isHealthy ? 'bg-green-500' : 'bg-red-500';
157
+ const statusText = isHealthy ? 'Configured' : 'Not Configured';
158
+ const html = '<span class="pulse-dot w-2 h-2 ' + statusColor + ' rounded-full"></span>' +
159
+ '<span class="text-xs font-medium text-gray-600 dark:text-gray-400">' + statusText + '</span>';
160
+ indicator.innerHTML = html;
161
+ }
162
+
163
+ this.updateSystemStatus(health);
164
+ }
165
+
166
+ // Also load live server info
167
+ await this.loadServerInfo();
168
+ } catch (error) {
169
+ console.error('Error loading health status:', error);
170
+ }
171
+ }
172
+
173
+ async loadServerInfo() {
174
+ try {
175
+ console.log('Loading Centrifugo server info...');
176
+
177
+ // Call Server API to get live stats
178
+ const response = await this.api.centrifugoAdminApiServerInfoCreate();
179
+
180
+ if (response && response.result && response.result.nodes && response.result.nodes.length > 0) {
181
+ const node = response.result.nodes[0]; // First node
182
+
183
+ // Update server version and uptime
184
+ this.updateElement('server-version-text', `${node.name} v${node.version}`);
185
+ this.updateElement('server-uptime-text', `Uptime: ${this.formatUptime(node.uptime)}`);
186
+
187
+ // Update live connection stats
188
+ this.updateElement('live-clients-count', node.num_clients.toLocaleString());
189
+ this.updateElement('live-users-count', node.num_users.toLocaleString());
190
+ this.updateElement('live-channels-count', node.num_channels.toLocaleString());
191
+ this.updateElement('live-subs-count', node.num_subs.toLocaleString());
192
+
193
+ // Update server status icon
194
+ const serverIcon = document.getElementById('server-status-icon');
195
+ if (serverIcon) {
196
+ serverIcon.className = 'material-icons flex-shrink-0 text-2xl text-green-500';
197
+ serverIcon.textContent = 'check_circle';
198
+ }
199
+
200
+ console.log('Server info loaded:', node);
201
+ } else if (response && response.error) {
202
+ console.error('Server API error:', response.error);
203
+ this.showServerError(response.error.message);
204
+ }
205
+ } catch (error) {
206
+ console.error('Failed to load server info:', error);
207
+ this.showServerError('Failed to connect to Centrifugo server');
208
+ }
209
+ }
210
+
211
+ formatUptime(seconds) {
212
+ const days = Math.floor(seconds / 86400);
213
+ const hours = Math.floor((seconds % 86400) / 3600);
214
+ const minutes = Math.floor((seconds % 3600) / 60);
215
+
216
+ if (days > 0) {
217
+ return `${days}d ${hours}h ${minutes}m`;
218
+ } else if (hours > 0) {
219
+ return `${hours}h ${minutes}m`;
220
+ } else {
221
+ return `${minutes}m`;
222
+ }
223
+ }
224
+
225
+ showServerError(message) {
226
+ this.updateElement('server-version-text', 'Offline');
227
+ this.updateElement('server-uptime-text', message);
228
+ this.updateElement('live-clients-count', '?');
229
+ this.updateElement('live-users-count', '?');
230
+ this.updateElement('live-channels-count', '?');
231
+ this.updateElement('live-subs-count', '?');
232
+
233
+ const serverIcon = document.getElementById('server-status-icon');
234
+ if (serverIcon) {
235
+ serverIcon.className = 'material-icons flex-shrink-0 text-2xl text-red-500';
236
+ serverIcon.textContent = 'error';
237
+ }
238
+ }
239
+
240
+ updateSystemStatus(health) {
241
+ const statusContainer = document.getElementById('system-status');
242
+ if (!statusContainer) return;
243
+
244
+ // Wrapper status
245
+ const wrapperColor = health.wrapper_url ? 'text-green-500' : 'text-gray-500';
246
+ const wrapperIcon = health.wrapper_url ? 'link' : 'link_off';
247
+
248
+ // Configuration status (API key)
249
+ const configColor = health.has_api_key ? 'text-green-500' : 'text-yellow-500';
250
+ const configIcon = health.has_api_key ? 'vpn_key' : 'warning';
251
+ const configStatus = health.has_api_key ? 'API Key Configured' : 'No API Key';
252
+
253
+ let html = '<div class="flex items-start gap-3">';
254
+ html += '<span class="material-icons flex-shrink-0 text-2xl ' + wrapperColor + '">' + wrapperIcon + '</span>';
255
+ html += '<div class="min-w-0">';
256
+ html += '<p class="text-sm font-medium text-gray-900 dark:text-white">Centrifugo Wrapper</p>';
257
+ html += '<p class="text-xs text-gray-600 dark:text-gray-400 break-all">' + (health.wrapper_url || 'Not configured') + '</p>';
258
+ html += '</div></div>';
259
+
260
+ html += '<div class="flex items-start gap-3">';
261
+ html += '<span class="material-icons flex-shrink-0 text-2xl ' + configColor + '">' + configIcon + '</span>';
262
+ html += '<div class="min-w-0">';
263
+ html += '<p class="text-sm font-medium text-gray-900 dark:text-white">Configuration</p>';
264
+ html += '<p class="text-xs text-gray-600 dark:text-gray-400">' + configStatus + '</p>';
265
+ html += '</div></div>';
266
+
267
+ statusContainer.innerHTML = html;
268
+ }
269
+
270
+ updateLastUpdate() {
271
+ const element = document.getElementById('last-update');
272
+ if (element) {
273
+ const now = new Date();
274
+ element.textContent = 'Last updated: ' + now.toLocaleTimeString();
275
+ }
276
+ }
277
+
278
+ startAutoRefresh() {
279
+ if (this.refreshInterval) {
280
+ clearInterval(this.refreshInterval);
281
+ }
282
+
283
+ this.refreshInterval = setInterval(() => {
284
+ if (this.autoRefresh) {
285
+ this.loadHealthStatus();
286
+
287
+ // Don't refresh static tabs (usage-guide)
288
+ if (this.currentTab !== 'usage-guide') {
289
+ this.loadTabData(this.currentTab);
290
+ }
291
+ }
292
+ }, this.refreshRate);
293
+ }
294
+
295
+ stopAutoRefresh() {
296
+ if (this.refreshInterval) {
297
+ clearInterval(this.refreshInterval);
298
+ this.refreshInterval = null;
299
+ }
300
+ }
301
+
302
+ updateElement(id, value) {
303
+ const element = document.getElementById(id);
304
+ if (element) {
305
+ element.textContent = value;
306
+ }
307
+ }
308
+ }
309
+
310
+ async function initializeDashboard() {
311
+ console.log('DOM loaded, waiting for CentrifugoAPI...');
312
+
313
+ let attempts = 0;
314
+ const maxAttempts = 100;
315
+
316
+ while (!window.centrifugoAPI && attempts < maxAttempts) {
317
+ await new Promise(resolve => setTimeout(resolve, 50));
318
+ attempts++;
319
+ }
320
+
321
+ if (!window.centrifugoAPI) {
322
+ console.error('L CentrifugoAPI failed to load after 5 seconds');
323
+ return;
324
+ }
325
+
326
+ console.log(' CentrifugoAPI ready, initializing dashboard...');
327
+ window.centrifugoDashboard = new CentrifugoDashboard();
328
+ window.centrifugoDashboard.init();
329
+ }
330
+
331
+ document.addEventListener('DOMContentLoaded', initializeDashboard);
332
+
333
+ export default CentrifugoDashboard;