django-cfg 1.3.9__py3-none-any.whl → 1.3.11__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.
Files changed (187) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/payments/admin/networks_admin.py +12 -1
  3. django_cfg/apps/payments/admin/payments_admin.py +13 -0
  4. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +62 -14
  5. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  6. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  7. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  8. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  9. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  10. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  11. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  12. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +33 -3
  13. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  14. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +96 -45
  15. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  16. django_cfg/apps/payments/config/__init__.py +14 -15
  17. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  18. django_cfg/apps/payments/config/helpers.py +8 -13
  19. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  20. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  21. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  22. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  23. django_cfg/apps/payments/models/payments.py +94 -0
  24. django_cfg/apps/payments/services/core/base.py +4 -4
  25. django_cfg/apps/payments/services/core/payment_service.py +265 -38
  26. django_cfg/apps/payments/services/providers/base.py +209 -3
  27. django_cfg/apps/payments/services/providers/models/__init__.py +2 -0
  28. django_cfg/apps/payments/services/providers/models/base.py +25 -2
  29. django_cfg/apps/payments/services/providers/nowpayments/models.py +2 -2
  30. django_cfg/apps/payments/services/providers/nowpayments/provider.py +57 -9
  31. django_cfg/apps/payments/services/providers/registry.py +5 -5
  32. django_cfg/apps/payments/services/types/requests.py +19 -7
  33. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  34. django_cfg/apps/payments/static/payments/js/api-client.js +6 -1
  35. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  36. django_cfg/apps/payments/static/payments/js/payment-form.js +35 -26
  37. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  38. django_cfg/apps/payments/urls.py +3 -2
  39. django_cfg/apps/payments/views/api/currencies.py +3 -0
  40. django_cfg/apps/payments/views/serializers/currencies.py +18 -5
  41. django_cfg/apps/tasks/admin/tasks_admin.py +2 -2
  42. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  43. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  44. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  45. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  46. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  47. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  48. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  49. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  50. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  51. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  52. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  53. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  54. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  55. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  56. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  57. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  58. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  59. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  60. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  61. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  62. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  63. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  64. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  65. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  66. django_cfg/apps/tasks/urls.py +2 -2
  67. django_cfg/apps/tasks/urls_admin.py +2 -2
  68. django_cfg/apps/tasks/utils/__init__.py +1 -0
  69. django_cfg/apps/tasks/utils/simulator.py +356 -0
  70. django_cfg/apps/tasks/views/__init__.py +16 -0
  71. django_cfg/apps/tasks/views/api.py +569 -0
  72. django_cfg/apps/tasks/views/dashboard.py +58 -0
  73. django_cfg/core/integration/__init__.py +21 -0
  74. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  75. django_cfg/models/constance.py +0 -11
  76. django_cfg/models/payments.py +137 -3
  77. django_cfg/modules/django_tasks.py +54 -21
  78. django_cfg/registry/core.py +4 -9
  79. django_cfg/template_archive/django_sample.zip +0 -0
  80. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -2
  81. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/RECORD +84 -152
  82. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  83. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  84. django_cfg/apps/payments/config/constance/fields.py +0 -69
  85. django_cfg/apps/payments/config/constance/settings.py +0 -160
  86. django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +0 -26
  87. django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +0 -28
  88. django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +0 -30
  89. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  90. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  91. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  92. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  93. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  94. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  95. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  96. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  97. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  98. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  99. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  100. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  101. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  102. django_cfg/apps/tasks/views.py +0 -461
  103. django_cfg/management/commands/app_agent_diagnose.py +0 -470
  104. django_cfg/management/commands/app_agent_generate.py +0 -342
  105. django_cfg/management/commands/app_agent_info.py +0 -308
  106. django_cfg/management/commands/auto_generate.py +0 -486
  107. django_cfg/modules/django_app_agent/__init__.py +0 -87
  108. django_cfg/modules/django_app_agent/agents/__init__.py +0 -40
  109. django_cfg/modules/django_app_agent/agents/base/__init__.py +0 -24
  110. django_cfg/modules/django_app_agent/agents/base/agent.py +0 -354
  111. django_cfg/modules/django_app_agent/agents/base/context.py +0 -236
  112. django_cfg/modules/django_app_agent/agents/base/executor.py +0 -430
  113. django_cfg/modules/django_app_agent/agents/generation/__init__.py +0 -12
  114. django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +0 -15
  115. django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +0 -147
  116. django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +0 -99
  117. django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +0 -32
  118. django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +0 -290
  119. django_cfg/modules/django_app_agent/agents/interfaces.py +0 -376
  120. django_cfg/modules/django_app_agent/core/__init__.py +0 -33
  121. django_cfg/modules/django_app_agent/core/config.py +0 -300
  122. django_cfg/modules/django_app_agent/core/exceptions.py +0 -359
  123. django_cfg/modules/django_app_agent/models/__init__.py +0 -71
  124. django_cfg/modules/django_app_agent/models/base.py +0 -283
  125. django_cfg/modules/django_app_agent/models/context.py +0 -496
  126. django_cfg/modules/django_app_agent/models/enums.py +0 -481
  127. django_cfg/modules/django_app_agent/models/requests.py +0 -500
  128. django_cfg/modules/django_app_agent/models/responses.py +0 -585
  129. django_cfg/modules/django_app_agent/pytest.ini +0 -6
  130. django_cfg/modules/django_app_agent/services/__init__.py +0 -42
  131. django_cfg/modules/django_app_agent/services/app_generator/__init__.py +0 -30
  132. django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +0 -133
  133. django_cfg/modules/django_app_agent/services/app_generator/context.py +0 -40
  134. django_cfg/modules/django_app_agent/services/app_generator/main.py +0 -202
  135. django_cfg/modules/django_app_agent/services/app_generator/structure.py +0 -316
  136. django_cfg/modules/django_app_agent/services/app_generator/validation.py +0 -125
  137. django_cfg/modules/django_app_agent/services/base.py +0 -437
  138. django_cfg/modules/django_app_agent/services/context_builder/__init__.py +0 -34
  139. django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +0 -141
  140. django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +0 -276
  141. django_cfg/modules/django_app_agent/services/context_builder/main.py +0 -272
  142. django_cfg/modules/django_app_agent/services/context_builder/models.py +0 -40
  143. django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +0 -85
  144. django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +0 -31
  145. django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +0 -311
  146. django_cfg/modules/django_app_agent/services/project_scanner/main.py +0 -221
  147. django_cfg/modules/django_app_agent/services/project_scanner/models.py +0 -59
  148. django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +0 -94
  149. django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +0 -28
  150. django_cfg/modules/django_app_agent/services/questioning_service/main.py +0 -273
  151. django_cfg/modules/django_app_agent/services/questioning_service/models.py +0 -111
  152. django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +0 -251
  153. django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +0 -347
  154. django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +0 -356
  155. django_cfg/modules/django_app_agent/services/report_service.py +0 -332
  156. django_cfg/modules/django_app_agent/services/template_manager/__init__.py +0 -18
  157. django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +0 -236
  158. django_cfg/modules/django_app_agent/services/template_manager/main.py +0 -159
  159. django_cfg/modules/django_app_agent/services/template_manager/models.py +0 -36
  160. django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +0 -100
  161. django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +0 -105
  162. django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +0 -31
  163. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +0 -44
  164. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +0 -81
  165. django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +0 -107
  166. django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +0 -139
  167. django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +0 -91
  168. django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +0 -195
  169. django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +0 -35
  170. django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +0 -211
  171. django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +0 -200
  172. django_cfg/modules/django_app_agent/services/validation_service/__init__.py +0 -25
  173. django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +0 -333
  174. django_cfg/modules/django_app_agent/services/validation_service/main.py +0 -242
  175. django_cfg/modules/django_app_agent/services/validation_service/models.py +0 -66
  176. django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +0 -352
  177. django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +0 -272
  178. django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +0 -203
  179. django_cfg/modules/django_app_agent/ui/__init__.py +0 -25
  180. django_cfg/modules/django_app_agent/ui/cli.py +0 -419
  181. django_cfg/modules/django_app_agent/ui/rich_components.py +0 -622
  182. django_cfg/modules/django_app_agent/utils/__init__.py +0 -38
  183. django_cfg/modules/django_app_agent/utils/logging.py +0 -360
  184. django_cfg/modules/django_app_agent/utils/validation.py +0 -417
  185. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  186. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  187. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * TaskRenderer - Renders tasks using HTML templates (no HTML in JS!)
3
+ */
4
+ export class TaskRenderer {
5
+ constructor() {
6
+ this.taskRowTemplate = document.getElementById('task-row-template');
7
+ this.statusConfig = {
8
+ pending: {
9
+ icon: 'schedule',
10
+ label: 'PENDING',
11
+ color: 'bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200',
12
+ iconColor: 'text-yellow-500'
13
+ },
14
+ running: {
15
+ icon: 'play_circle',
16
+ label: 'RUNNING',
17
+ color: 'bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200',
18
+ iconColor: 'text-blue-500'
19
+ },
20
+ completed: {
21
+ icon: 'check_circle',
22
+ label: 'COMPLETED',
23
+ color: 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200',
24
+ iconColor: 'text-green-500'
25
+ },
26
+ failed: {
27
+ icon: 'error',
28
+ label: 'FAILED',
29
+ color: 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200',
30
+ iconColor: 'text-red-500'
31
+ }
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Render tasks into the table
37
+ * @param {Array} tasks - Array of task objects
38
+ * @param {HTMLElement} container - Container element
39
+ */
40
+ renderTasks(tasks, container) {
41
+ const tableBody = container.querySelector('#task-table-body');
42
+ if (!tableBody) return;
43
+
44
+ // Clear existing rows
45
+ tableBody.innerHTML = '';
46
+
47
+ // Render each task
48
+ tasks.forEach(task => {
49
+ const row = this.createTaskRow(task);
50
+ if (row) {
51
+ tableBody.appendChild(row);
52
+ }
53
+ });
54
+ }
55
+
56
+ /**
57
+ * Create a task row element using template
58
+ * @param {Object} task - Task object
59
+ * @returns {HTMLElement} - Task row element
60
+ */
61
+ createTaskRow(task) {
62
+ if (!this.taskRowTemplate) {
63
+ console.error('Task row template not found');
64
+ return null;
65
+ }
66
+
67
+ // Clone template
68
+ const row = this.taskRowTemplate.content.cloneNode(true).querySelector('.task-row');
69
+
70
+ // Set task ID
71
+ row.setAttribute('data-task-id', task.id);
72
+
73
+ // Map status
74
+ const displayStatus = this.mapStatus(task.status);
75
+ const statusConfig = this.statusConfig[displayStatus];
76
+
77
+ // Populate status
78
+ const statusIcon = row.querySelector('.task-status-icon');
79
+ const statusBadge = row.querySelector('.task-status-badge');
80
+
81
+ if (statusIcon && statusBadge && statusConfig) {
82
+ statusIcon.textContent = statusConfig.icon;
83
+ statusIcon.className = `material-icons text-sm ${statusConfig.iconColor}`;
84
+
85
+ statusBadge.textContent = statusConfig.label;
86
+ statusBadge.className = `px-2 py-1 text-xs font-medium rounded-full ${statusConfig.color}`;
87
+ }
88
+
89
+ // Show progress bar for running tasks
90
+ if (displayStatus === 'running' && task.progress) {
91
+ const progressContainer = row.querySelector('.task-progress');
92
+ const progressBar = progressContainer?.querySelector('div');
93
+ if (progressContainer && progressBar) {
94
+ progressContainer.classList.remove('hidden');
95
+ progressBar.style.width = `${task.progress}%`;
96
+ }
97
+ }
98
+
99
+ // Populate task info
100
+ const taskName = row.querySelector('.task-name');
101
+ const taskId = row.querySelector('.task-id');
102
+ if (taskName) taskName.textContent = task.actor_name || 'Unknown Task';
103
+ if (taskId) taskId.textContent = `${String(task.id).substring(0, 8)}...`;
104
+
105
+ // Populate queue
106
+ const taskQueue = row.querySelector('.task-queue');
107
+ if (taskQueue) taskQueue.textContent = task.queue_name || task.queue || 'unknown';
108
+
109
+ // Populate duration and time
110
+ const taskDuration = row.querySelector('.task-duration');
111
+ const taskUpdated = row.querySelector('.task-updated');
112
+ if (taskDuration) taskDuration.textContent = this.calculateDuration(task.created_at, task.updated_at);
113
+ if (taskUpdated) taskUpdated.textContent = new Date(task.updated_at).toLocaleTimeString();
114
+
115
+ // Populate actions
116
+ this.populateActions(row, task, displayStatus);
117
+
118
+ return row;
119
+ }
120
+
121
+ /**
122
+ * Map task status to display status
123
+ * @param {string} status - Original status
124
+ * @returns {string} - Mapped status
125
+ */
126
+ mapStatus(status) {
127
+ const statusMap = {
128
+ 'enqueued': 'pending',
129
+ 'delayed': 'pending',
130
+ 'pending': 'pending',
131
+ 'running': 'running',
132
+ 'done': 'completed',
133
+ 'completed': 'completed',
134
+ 'failed': 'failed',
135
+ 'skipped': 'completed'
136
+ };
137
+
138
+ return statusMap[status?.toLowerCase()] || 'pending';
139
+ }
140
+
141
+ /**
142
+ * Populate task actions (no HTML strings!)
143
+ * @param {HTMLElement} row - Task row element
144
+ * @param {Object} task - Task object
145
+ * @param {string} displayStatus - Display status
146
+ */
147
+ populateActions(row, task, displayStatus) {
148
+ const actionsContainer = row.querySelector('.task-actions');
149
+ if (!actionsContainer) return;
150
+
151
+ actionsContainer.innerHTML = '';
152
+
153
+ // Add retry button for failed tasks
154
+ if (displayStatus === 'failed') {
155
+ const retryBtn = document.createElement('button');
156
+ retryBtn.className = 'px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors';
157
+ retryBtn.textContent = 'Retry';
158
+ retryBtn.addEventListener('click', () => this.retryTask(task.id));
159
+ actionsContainer.appendChild(retryBtn);
160
+ }
161
+
162
+ // Add details button if task has additional info
163
+ if (task.args || task.kwargs || task.result || task.traceback) {
164
+ const detailsBtn = document.createElement('button');
165
+ detailsBtn.className = 'p-1 text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded transition-colors';
166
+ detailsBtn.title = 'Show details';
167
+
168
+ const icon = document.createElement('span');
169
+ icon.className = 'material-icons text-sm';
170
+ icon.textContent = 'info';
171
+ detailsBtn.appendChild(icon);
172
+
173
+ detailsBtn.addEventListener('click', () => this.showTaskDetails(task));
174
+ actionsContainer.appendChild(detailsBtn);
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Calculate duration between two dates
180
+ * @param {string} startTime - Start time ISO string
181
+ * @param {string} endTime - End time ISO string
182
+ * @returns {string} - Formatted duration
183
+ */
184
+ calculateDuration(startTime, endTime) {
185
+ if (!startTime || !endTime) return '--';
186
+
187
+ const start = new Date(startTime);
188
+ const end = new Date(endTime);
189
+ const diff = end - start;
190
+
191
+ if (diff < 1000) return `${diff}ms`;
192
+ if (diff < 60000) return `${Math.floor(diff / 1000)}s`;
193
+ if (diff < 3600000) return `${Math.floor(diff / 60000)}m ${Math.floor((diff % 60000) / 1000)}s`;
194
+ return `${Math.floor(diff / 3600000)}h ${Math.floor((diff % 3600000) / 60000)}m`;
195
+ }
196
+
197
+ /**
198
+ * Retry a failed task
199
+ * @param {string} taskId - Task ID
200
+ */
201
+ retryTask(taskId) {
202
+ console.log('Retrying task:', taskId);
203
+ // TODO: Implement retry functionality
204
+ alert(`Retry functionality for task ${taskId} will be implemented`);
205
+ }
206
+
207
+ /**
208
+ * Show task details
209
+ * @param {Object} task - Task object
210
+ */
211
+ showTaskDetails(task) {
212
+ console.log('Showing task details:', task);
213
+ // TODO: Implement task details modal
214
+ alert(`Task Details:\nID: ${task.id}\nActor: ${task.actor_name}\nStatus: ${task.status}`);
215
+ }
216
+ }
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Main Tasks Dashboard Controller
3
+ * Orchestrates all dashboard modules
4
+ */
5
+ import { OverviewModule } from './overview.mjs';
6
+ import { QueuesModule } from './queues.mjs';
7
+ import { WorkersModule } from './workers.mjs';
8
+ import { TasksModule } from './tasks.mjs';
9
+
10
+ class TasksDashboard {
11
+ constructor() {
12
+ this.api = window.tasksAPI;
13
+ this.currentTab = 'overview';
14
+ this.refreshInterval = null;
15
+ this.refreshRate = 30000; // 30 seconds
16
+
17
+ // Initialize modules (pass reference to this dashboard for badge updates)
18
+ this.overviewModule = new OverviewModule(this.api, this);
19
+ this.queuesModule = new QueuesModule(this.api, this);
20
+ this.workersModule = new WorkersModule(this.api, this);
21
+ this.tasksModule = new TasksModule(this.api, this);
22
+ }
23
+
24
+ /**
25
+ * Initialize dashboard
26
+ */
27
+ init() {
28
+ console.log('Initializing Tasks Dashboard...');
29
+ this.setupEventListeners();
30
+ this.loadInitialData();
31
+ this.startAutoRefresh();
32
+ }
33
+
34
+ /**
35
+ * Setup event listeners
36
+ */
37
+ setupEventListeners() {
38
+ // Tab buttons
39
+ document.querySelectorAll('.tab-button').forEach(button => {
40
+ button.addEventListener('click', (e) => {
41
+ const tabId = e.currentTarget.dataset.tab;
42
+ this.switchTab(tabId);
43
+ });
44
+ });
45
+
46
+ // Management actions
47
+ document.getElementById('simulate-data-btn')?.addEventListener('click', () => this.simulateData());
48
+ document.getElementById('clear-test-data-btn')?.addEventListener('click', () => this.clearData());
49
+ document.getElementById('clear-all-queues-btn')?.addEventListener('click', () => this.clearQueues());
50
+ document.getElementById('purge-failed-tasks-btn')?.addEventListener('click', () => this.purgeFailed());
51
+ }
52
+
53
+ /**
54
+ * Switch tabs
55
+ */
56
+ switchTab(tabId) {
57
+ console.log('Switching to tab:', tabId);
58
+
59
+ // Update active tab styling
60
+ document.querySelectorAll('.tab-button').forEach(tab => {
61
+ tab.classList.remove('active');
62
+ tab.classList.add('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300', 'dark:text-gray-400', 'dark:hover:text-gray-300');
63
+ });
64
+
65
+ // Add active to selected tab
66
+ const activeTab = document.querySelector(`[data-tab="${tabId}"]`);
67
+ if (activeTab) {
68
+ activeTab.classList.remove('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300', 'dark:text-gray-400', 'dark:hover:text-gray-300');
69
+ activeTab.classList.add('active');
70
+ }
71
+
72
+ // Hide all tab panels
73
+ document.querySelectorAll('.tab-panel').forEach(panel => {
74
+ panel.classList.add('hidden');
75
+ panel.classList.remove('active');
76
+ });
77
+
78
+ // Show selected tab panel
79
+ const activePanel = document.querySelector(`#${tabId}-tab`);
80
+ if (activePanel) {
81
+ activePanel.classList.remove('hidden');
82
+ activePanel.classList.add('active');
83
+ }
84
+
85
+ this.currentTab = tabId;
86
+ this.loadTabData(tabId);
87
+ }
88
+
89
+ /**
90
+ * Load initial data
91
+ */
92
+ async loadInitialData() {
93
+ console.log('Loading initial data...');
94
+ await this.loadTabData(this.currentTab);
95
+ }
96
+
97
+ /**
98
+ * Load data for specific tab using modules
99
+ */
100
+ async loadTabData(tabId) {
101
+ console.log('Loading data for tab:', tabId);
102
+
103
+ switch (tabId) {
104
+ case 'overview':
105
+ await this.overviewModule.loadData();
106
+ break;
107
+ case 'queues':
108
+ await this.queuesModule.loadData();
109
+ break;
110
+ case 'workers':
111
+ await this.workersModule.loadData();
112
+ break;
113
+ case 'tasks':
114
+ await this.tasksModule.loadData();
115
+ break;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Management actions
121
+ */
122
+ async simulateData() {
123
+ try {
124
+ this.showManagementActionStatus('Simulating test data...', 'info');
125
+ const response = await this.api.simulateData();
126
+
127
+ if (response.success) {
128
+ this.showManagementActionStatus('Test data simulation completed successfully', 'success');
129
+ await this.loadTabData(this.currentTab);
130
+ } else {
131
+ this.showManagementActionStatus(`Simulation failed: ${response.error}`, 'error');
132
+ }
133
+ } catch (error) {
134
+ this.showManagementActionStatus(`Simulation error: ${error.message}`, 'error');
135
+ }
136
+ }
137
+
138
+ async clearData() {
139
+ try {
140
+ this.showManagementActionStatus('Clearing test data...', 'info');
141
+ const response = await this.api.clearData();
142
+
143
+ if (response.success) {
144
+ this.showManagementActionStatus('Test data cleared successfully', 'success');
145
+ await this.loadTabData(this.currentTab);
146
+ } else {
147
+ this.showManagementActionStatus(`Clear failed: ${response.error}`, 'error');
148
+ }
149
+ } catch (error) {
150
+ this.showManagementActionStatus(`Clear error: ${error.message}`, 'error');
151
+ }
152
+ }
153
+
154
+ async clearQueues() {
155
+ console.log('Clearing queues...');
156
+ this.showManagementActionStatus('Clearing all queues...', 'info');
157
+ try {
158
+ const response = await this.api.clearQueues();
159
+ if (response.success) {
160
+ this.showManagementActionStatus(response.message, 'success');
161
+ this.loadTabData(this.currentTab);
162
+ } else {
163
+ this.showManagementActionStatus(`Failed to clear queues: ${response.error}`, 'error');
164
+ }
165
+ } catch (error) {
166
+ this.showManagementActionStatus(`Failed to clear queues: ${error.message}`, 'error');
167
+ }
168
+ }
169
+
170
+ async purgeFailed() {
171
+ console.log('Purging failed tasks...');
172
+ this.showManagementActionStatus('Purging failed tasks...', 'info');
173
+ try {
174
+ const response = await this.api.purgeFailed();
175
+ if (response.success) {
176
+ this.showManagementActionStatus(response.message, 'success');
177
+ this.loadTabData(this.currentTab);
178
+ } else {
179
+ this.showManagementActionStatus(`Failed to purge failed tasks: ${response.error}`, 'error');
180
+ }
181
+ } catch (error) {
182
+ this.showManagementActionStatus(`Failed to purge failed tasks: ${error.message}`, 'error');
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Show management action status
188
+ */
189
+ showManagementActionStatus(message, type = 'info') {
190
+ const statusDiv = document.getElementById('management-action-status');
191
+ const messageSpan = document.getElementById('management-action-message');
192
+
193
+ if (statusDiv && messageSpan) {
194
+ messageSpan.textContent = message;
195
+ statusDiv.classList.remove('hidden');
196
+
197
+ setTimeout(() => {
198
+ statusDiv.classList.add('hidden');
199
+ }, 5000);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Update tab badges with counts
205
+ */
206
+ updateTabBadges(data) {
207
+ // Update queues badge
208
+ const queuesBadge = document.querySelector('#queues-count-badge');
209
+ if (queuesBadge && data.active_queues !== undefined) {
210
+ queuesBadge.textContent = data.active_queues;
211
+ }
212
+
213
+ // Update workers badge
214
+ const workersBadge = document.querySelector('#workers-count-badge');
215
+ if (workersBadge && data.workers !== undefined) {
216
+ workersBadge.textContent = data.workers;
217
+ }
218
+
219
+ // Update tasks badge - will be updated by tasks module
220
+ const tasksBadge = document.querySelector('#tasks-count-badge');
221
+ if (tasksBadge && data.total_tasks !== undefined) {
222
+ tasksBadge.textContent = data.total_tasks;
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Start auto-refresh
228
+ */
229
+ startAutoRefresh() {
230
+ if (this.refreshInterval) {
231
+ clearInterval(this.refreshInterval);
232
+ }
233
+
234
+ this.refreshInterval = setInterval(() => {
235
+ this.loadTabData(this.currentTab);
236
+ }, this.refreshRate);
237
+ }
238
+ }
239
+
240
+ // Initialize dashboard when DOM is ready
241
+ document.addEventListener('DOMContentLoaded', () => {
242
+ console.log('DOM loaded, initializing dashboard...');
243
+ window.dashboard = new TasksDashboard();
244
+ window.dashboard.init();
245
+ });
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Overview Dashboard Module
3
+ * Handles overview tab functionality
4
+ */
5
+ export class OverviewModule {
6
+ constructor(api, dashboard) {
7
+ this.api = api;
8
+ this.dashboard = dashboard; // Reference to main dashboard for badge updates
9
+ }
10
+
11
+ /**
12
+ * Load overview data
13
+ */
14
+ async loadData() {
15
+ try {
16
+ console.log('Loading overview data...');
17
+
18
+ const [queueData, taskStats] = await Promise.all([
19
+ this.api.getQueueStatus(),
20
+ this.api.getTaskStatistics()
21
+ ]);
22
+
23
+ const queueInfo = queueData.data || queueData;
24
+ const taskInfo = taskStats.data || taskStats;
25
+
26
+ this.updateStatusCards(queueInfo, taskInfo);
27
+ this.updateSystemStatus(queueInfo);
28
+
29
+ // Update tab badges
30
+ if (this.dashboard && this.dashboard.updateTabBadges) {
31
+ this.dashboard.updateTabBadges(queueInfo);
32
+ }
33
+
34
+ } catch (error) {
35
+ console.error('Failed to load overview data:', error);
36
+ this.showError('Failed to load overview data');
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Update status cards
42
+ */
43
+ updateStatusCards(queueData, taskData) {
44
+ this.updateElement('active-queues-count', queueData.active_queues || 0);
45
+ this.updateElement('workers-count', queueData.workers || 0);
46
+ this.updateElement('pending-tasks-count', queueData.total_pending || 0);
47
+ this.updateElement('failed-tasks-count', queueData.total_failed || 0);
48
+ }
49
+
50
+ /**
51
+ * Update system status
52
+ */
53
+ updateSystemStatus(data) {
54
+ const statusContainer = document.getElementById('system-status');
55
+ if (!statusContainer) return;
56
+
57
+ const isHealthy = data.redis_connected && !data.error;
58
+ const timestamp = new Date().toLocaleTimeString();
59
+
60
+ statusContainer.innerHTML = `
61
+ <div class="flex items-center justify-between mb-4">
62
+ <div class="flex items-center">
63
+ <span class="material-icons text-2xl mr-3 ${isHealthy ? 'text-green-600' : 'text-red-600'}">
64
+ ${isHealthy ? 'check_circle' : 'error'}
65
+ </span>
66
+ <div>
67
+ <h3 class="text-lg font-semibold ${isHealthy ? 'text-green-800' : 'text-red-800'} dark:${isHealthy ? 'text-green-200' : 'text-red-200'}">
68
+ ${isHealthy ? 'System Healthy' : 'System Issues Detected'}
69
+ </h3>
70
+ <p class="text-sm text-gray-600 dark:text-gray-400">
71
+ ${isHealthy ? 'All systems operational' : 'Some components need attention'}
72
+ </p>
73
+ </div>
74
+ </div>
75
+ <span class="text-xs text-gray-500 dark:text-gray-400">Last updated: ${timestamp}</span>
76
+ </div>
77
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
78
+ <div class="flex items-center">
79
+ <span class="material-icons text-base mr-2 ${data.redis_connected ? 'text-green-500' : 'text-red-500'}">
80
+ ${data.redis_connected ? 'check' : 'close'}
81
+ </span>
82
+ <span class="text-gray-700 dark:text-gray-300">Redis: ${data.redis_connected ? 'Connected' : 'Disconnected'}</span>
83
+ </div>
84
+ <div class="flex items-center">
85
+ <span class="material-icons text-base mr-2 ${data.workers > 0 ? 'text-green-500' : 'text-red-500'}">
86
+ ${data.workers > 0 ? 'check' : 'close'}
87
+ </span>
88
+ <span class="text-gray-700 dark:text-gray-300">Workers: ${data.workers} active</span>
89
+ </div>
90
+ <div class="flex items-center">
91
+ <span class="material-icons text-base mr-2 ${data.active_queues > 0 ? 'text-blue-500' : 'text-gray-500'}">queue</span>
92
+ <span class="text-gray-700 dark:text-gray-300">Queues: ${data.active_queues || 0} configured</span>
93
+ </div>
94
+ </div>
95
+ `;
96
+ }
97
+
98
+ /**
99
+ * Helper method to update element text
100
+ */
101
+ updateElement(id, value) {
102
+ const element = document.getElementById(id);
103
+ if (element) {
104
+ element.textContent = value;
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Show error message
110
+ */
111
+ showError(message) {
112
+ console.error(message);
113
+ const statusContainer = document.getElementById('system-status');
114
+ if (statusContainer) {
115
+ statusContainer.innerHTML = `
116
+ <div class="text-center py-8">
117
+ <span class="material-icons text-4xl text-red-400 mb-4">error</span>
118
+ <p class="text-red-600 dark:text-red-400">${message}</p>
119
+ </div>
120
+ `;
121
+ }
122
+ }
123
+ }