django-cfg 1.4.106__py3-none-any.whl → 1.4.108__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 (137) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/views/profile.py +19 -9
  3. django_cfg/apps/centrifugo/views/admin_api.py +4 -7
  4. django_cfg/apps/centrifugo/views/monitoring.py +3 -6
  5. django_cfg/apps/centrifugo/views/testing_api.py +3 -6
  6. django_cfg/apps/dashboard/services/system_health_service.py +16 -11
  7. django_cfg/apps/dashboard/views/activity_views.py +3 -5
  8. django_cfg/apps/dashboard/views/apizones_views.py +4 -5
  9. django_cfg/apps/dashboard/views/charts_views.py +4 -5
  10. django_cfg/apps/dashboard/views/overview_views.py +4 -5
  11. django_cfg/apps/dashboard/views/statistics_views.py +4 -5
  12. django_cfg/apps/dashboard/views/system_views.py +4 -5
  13. django_cfg/apps/knowbase/__init__.py +2 -2
  14. django_cfg/apps/knowbase/apps.py +2 -8
  15. django_cfg/apps/knowbase/views/base.py +9 -4
  16. django_cfg/apps/support/views/api.py +16 -7
  17. django_cfg/apps/tasks/__init__.py +61 -2
  18. django_cfg/apps/tasks/admin/__init__.py +3 -10
  19. django_cfg/apps/tasks/admin/config.py +98 -0
  20. django_cfg/apps/tasks/admin/task_log.py +265 -0
  21. django_cfg/apps/tasks/apps.py +7 -9
  22. django_cfg/apps/tasks/filters/__init__.py +10 -0
  23. django_cfg/apps/tasks/filters/task_log.py +121 -0
  24. django_cfg/apps/tasks/migrations/0001_initial.py +196 -0
  25. django_cfg/apps/tasks/models/__init__.py +4 -0
  26. django_cfg/apps/tasks/models/task_log.py +246 -0
  27. django_cfg/apps/tasks/serializers/__init__.py +28 -0
  28. django_cfg/apps/tasks/serializers/task_log.py +249 -0
  29. django_cfg/apps/tasks/services/__init__.py +10 -0
  30. django_cfg/apps/tasks/services/client/__init__.py +7 -0
  31. django_cfg/apps/tasks/services/client/client.py +234 -0
  32. django_cfg/apps/tasks/services/config_helper.py +63 -0
  33. django_cfg/apps/tasks/services/sync.py +204 -0
  34. django_cfg/apps/tasks/urls.py +7 -13
  35. django_cfg/apps/tasks/views/__init__.py +4 -10
  36. django_cfg/apps/tasks/views/task_log.py +41 -0
  37. django_cfg/apps/tasks/views/task_log_base.py +41 -0
  38. django_cfg/apps/tasks/views/task_log_overview.py +100 -0
  39. django_cfg/apps/tasks/views/task_log_related.py +41 -0
  40. django_cfg/apps/tasks/views/task_log_stats.py +91 -0
  41. django_cfg/apps/tasks/views/task_log_timeline.py +81 -0
  42. django_cfg/apps/urls.py +0 -1
  43. django_cfg/cli/commands/info.py +1 -1
  44. django_cfg/cli/utils.py +1 -1
  45. django_cfg/core/base/config_model.py +1 -1
  46. django_cfg/core/builders/apps_builder.py +1 -1
  47. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  48. django_cfg/core/generation/integration_generators/tasks.py +14 -18
  49. django_cfg/core/generation/security_generators/crypto_fields.py +2 -1
  50. django_cfg/core/integration/display/startup.py +1 -1
  51. django_cfg/mixins/__init__.py +12 -0
  52. django_cfg/mixins/admin_api.py +37 -0
  53. django_cfg/mixins/client_api.py +39 -0
  54. django_cfg/models/django/constance.py +2 -8
  55. django_cfg/models/django/crypto_fields.py +13 -48
  56. django_cfg/models/tasks/__init__.py +8 -10
  57. django_cfg/models/tasks/backends.py +76 -207
  58. django_cfg/models/tasks/config.py +20 -127
  59. django_cfg/models/tasks/utils.py +17 -29
  60. django_cfg/modules/django_admin/RESOURCE_CONFIG_ENHANCEMENT.md +350 -0
  61. django_cfg/modules/django_admin/__init__.py +4 -0
  62. django_cfg/modules/django_admin/base/pydantic_admin.py +70 -15
  63. django_cfg/modules/django_admin/config/__init__.py +4 -0
  64. django_cfg/modules/django_admin/config/admin_config.py +13 -1
  65. django_cfg/modules/django_admin/config/background_task_config.py +76 -0
  66. django_cfg/modules/django_admin/config/resource_config.py +129 -0
  67. django_cfg/modules/django_client/management/commands/generate_client.py +13 -1
  68. django_cfg/modules/django_unfold/navigation.py +121 -22
  69. django_cfg/pyproject.toml +2 -2
  70. django_cfg/registry/core.py +1 -1
  71. django_cfg/static/frontend/admin.zip +0 -0
  72. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/METADATA +5 -3
  73. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/RECORD +77 -111
  74. django_cfg/apps/tasks/admin/actions.py +0 -29
  75. django_cfg/apps/tasks/admin/tasks_admin.py +0 -154
  76. django_cfg/apps/tasks/api/serializers.py +0 -82
  77. django_cfg/apps/tasks/api/views.py +0 -571
  78. django_cfg/apps/tasks/serializers.py +0 -82
  79. django_cfg/apps/tasks/static/tasks/css/dashboard-alpine.css +0 -299
  80. django_cfg/apps/tasks/static/tasks/css/dashboard.css +0 -120
  81. django_cfg/apps/tasks/static/tasks/js/alpine/README.md +0 -47
  82. django_cfg/apps/tasks/static/tasks/js/alpine/actions/index.js +0 -8
  83. django_cfg/apps/tasks/static/tasks/js/alpine/actions/management.js +0 -123
  84. django_cfg/apps/tasks/static/tasks/js/alpine/actions/pagination.js +0 -21
  85. django_cfg/apps/tasks/static/tasks/js/alpine/actions/tasks.js +0 -101
  86. django_cfg/apps/tasks/static/tasks/js/alpine/actions/workers.js +0 -59
  87. django_cfg/apps/tasks/static/tasks/js/alpine/computed.js +0 -35
  88. django_cfg/apps/tasks/static/tasks/js/alpine/index.js +0 -148
  89. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/index.js +0 -36
  90. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/overview.js +0 -37
  91. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/queues.js +0 -27
  92. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/tasks.js +0 -32
  93. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/workers.js +0 -21
  94. django_cfg/apps/tasks/static/tasks/js/alpine/state.js +0 -36
  95. django_cfg/apps/tasks/static/tasks/js/alpine/utils/formatters.js +0 -42
  96. django_cfg/apps/tasks/static/tasks/js/alpine/utils/helpers.js +0 -68
  97. django_cfg/apps/tasks/static/tasks/js/dashboard-alpine.js +0 -725
  98. django_cfg/apps/tasks/tasks/__init__.py +0 -10
  99. django_cfg/apps/tasks/tasks/demo_tasks.py +0 -127
  100. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +0 -71
  101. django_cfg/apps/tasks/templates/tasks/components/overview_content.html +0 -94
  102. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +0 -44
  103. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +0 -45
  104. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -151
  105. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +0 -61
  106. django_cfg/apps/tasks/templates/tasks/components/tasks_mjs_integration.html +0 -269
  107. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +0 -60
  108. django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -20
  109. django_cfg/apps/tasks/templates/tasks/pages/dashboard-improved.html +0 -168
  110. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +0 -77
  111. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +0 -40
  112. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +0 -40
  113. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +0 -86
  114. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +0 -90
  115. django_cfg/apps/tasks/urls_admin.py +0 -15
  116. django_cfg/apps/tasks/utils/__init__.py +0 -1
  117. django_cfg/apps/tasks/utils/simulator.py +0 -353
  118. django_cfg/apps/tasks/views/api.py +0 -571
  119. django_cfg/apps/tasks/views/dashboard.py +0 -89
  120. django_cfg/management/commands/rundramatiq.py +0 -24
  121. django_cfg/management/commands/rundramatiq_simulator.py +0 -22
  122. django_cfg/management/commands/task_clear.py +0 -25
  123. django_cfg/management/commands/task_status.py +0 -24
  124. django_cfg/modules/django_tasks/__init__.py +0 -29
  125. django_cfg/modules/django_tasks/dramatiq_setup.py +0 -20
  126. django_cfg/modules/django_tasks/factory.py +0 -127
  127. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  128. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +0 -253
  129. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +0 -436
  130. django_cfg/modules/django_tasks/management/commands/task_clear.py +0 -226
  131. django_cfg/modules/django_tasks/management/commands/task_status.py +0 -257
  132. django_cfg/modules/django_tasks/service.py +0 -281
  133. django_cfg/modules/django_tasks/settings.py +0 -107
  134. /django_cfg/{modules/django_tasks/management → apps/tasks/migrations}/__init__.py +0 -0
  135. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/WHEEL +0 -0
  136. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/entry_points.txt +0 -0
  137. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/licenses/LICENSE +0 -0
@@ -1,725 +0,0 @@
1
- /**
2
- * Tasks Dashboard Alpine.js Logic
3
- *
4
- * This file extends Alpine.js data and methods for the Tasks Dashboard.
5
- * It integrates with the tasksAPI to provide reactive state management.
6
- *
7
- * TODO: Refactor into modular structure:
8
- * - alpine/state.js - Initial state
9
- * - alpine/loaders/ - Data loading methods (loadOverview, loadQueues, loadWorkers, loadTasks)
10
- * - alpine/actions/ - User actions (simulate, clear, purge, start/stop workers, etc)
11
- * - alpine/utils/ - Utility functions (formatters, helpers)
12
- * - alpine/index.js - Main entry combining all modules
13
- *
14
- * Current size: 716 lines (needs decomposition for maintainability)
15
- */
16
-
17
- // Wait for Alpine.js to be available
18
- document.addEventListener('alpine:init', () => {
19
- console.log('🚀 Initializing Alpine.js Dashboard extensions...');
20
-
21
- // Extend Alpine.js global data/methods
22
- Alpine.data('tasksDashboard', () => ({
23
- // Alpine.js state for Tasks Dashboard
24
- activeTab: 'overview',
25
- loading: false,
26
- autoRefresh: true,
27
- autoRefreshInterval: null,
28
- lastUpdateTime: '--:--:--',
29
-
30
- // Data collections
31
- tasks: [],
32
- queues: [],
33
- workers: [],
34
- stats: {},
35
-
36
- // Filters
37
- filters: {
38
- status: '',
39
- queue: '',
40
- search: ''
41
- },
42
-
43
- // Counts for badges
44
- counts: {
45
- queues: 0,
46
- workers: 0,
47
- tasks: 0
48
- },
49
-
50
- // Action message state
51
- actionMessage: '',
52
- actionType: 'info', // 'info', 'success', 'error'
53
-
54
- // Modal state
55
- showTaskModal: false,
56
- selectedTask: null,
57
-
58
- // Pagination state
59
- pagination: {
60
- page: 1,
61
- page_size: 20,
62
- total_pages: 1,
63
- total_count: 0,
64
- has_next: false,
65
- has_previous: false
66
- },
67
-
68
- // Lifecycle init
69
- init() {
70
- console.log('🎯 Dashboard component initialized');
71
-
72
- // Initialize dashboard data
73
- this.loadDashboardData();
74
-
75
- // Start auto-refresh if enabled
76
- if (this.autoRefresh) {
77
- this.startAutoRefresh();
78
- }
79
-
80
- // Watch for tab changes
81
- this.$watch('activeTab', (value) => {
82
- console.log('Tab changed to:', value);
83
- this.onTabChange(value);
84
- });
85
- },
86
-
87
- // Computed properties
88
- get filteredTasks() {
89
- let filtered = this.tasks;
90
-
91
- // Apply status filter
92
- if (this.filters.status) {
93
- filtered = filtered.filter(task => task.status === this.filters.status);
94
- }
95
-
96
- // Apply queue filter
97
- if (this.filters.queue) {
98
- filtered = filtered.filter(task =>
99
- (task.queue || task.queue_name) === this.filters.queue
100
- );
101
- }
102
-
103
- // Apply search filter
104
- if (this.filters.search) {
105
- const search = this.filters.search.toLowerCase();
106
- filtered = filtered.filter(task =>
107
- task.name?.toLowerCase().includes(search) ||
108
- task.actor_name?.toLowerCase().includes(search) ||
109
- task.task_id?.toLowerCase().includes(search) ||
110
- task.message_id?.toLowerCase().includes(search) ||
111
- task.queue?.toLowerCase().includes(search) ||
112
- task.queue_name?.toLowerCase().includes(search)
113
- );
114
- }
115
-
116
- return filtered;
117
- },
118
-
119
- // Methods
120
- async loadDashboardData() {
121
- console.log('📊 Loading dashboard data...');
122
- this.loading = true;
123
-
124
- try {
125
- // Load all data in parallel
126
- await Promise.all([
127
- this.loadOverview(),
128
- this.loadQueues(),
129
- this.loadWorkers(),
130
- this.loadTasks()
131
- ]);
132
-
133
- this.updateLastUpdateTime();
134
- console.log('✅ Dashboard data loaded successfully');
135
- } catch (error) {
136
- console.error('❌ Failed to load dashboard data:', error);
137
- if (window.showNotification) {
138
- window.showNotification('Failed to load dashboard data', 'error');
139
- }
140
- } finally {
141
- this.loading = false;
142
- }
143
- },
144
-
145
- async loadOverview() {
146
- if (!window.tasksAPI) return;
147
-
148
- try {
149
- const response = await window.tasksAPI.tasksApiTasksStatsRetrieve();
150
- const data = response?.data || response || {};
151
-
152
- // Flatten statistics into stats for easier access in template
153
- if (data.statistics) {
154
- this.stats = {
155
- ...data,
156
- ...data.statistics,
157
- // Map API fields to template fields
158
- total_tasks: data.statistics.total || 0,
159
- completed_tasks: data.statistics.completed || 0,
160
- running_tasks: data.statistics.running || 0,
161
- failed_tasks: data.statistics.failed || 0,
162
- pending_tasks: data.statistics.pending || 0,
163
- success_rate: (data.statistics.success_rate || 0) / 100 // Convert from % to decimal
164
- };
165
- } else {
166
- this.stats = data;
167
- }
168
-
169
- // Update counts
170
- this.counts.queues = this.stats.active_queues || 0;
171
- // Note: workers count is updated in loadWorkers()
172
- this.counts.tasks = this.stats.total_tasks || 0;
173
-
174
- console.log('📈 Overview stats loaded:', this.stats);
175
- } catch (error) {
176
- console.error('Failed to load overview:', error);
177
- }
178
- },
179
-
180
- async loadQueues() {
181
- if (!window.tasksAPI) return;
182
-
183
- try {
184
- const response = await window.tasksAPI.tasksApiQueuesStatusRetrieve();
185
- const queuesData = response?.data?.queues || response?.queues;
186
-
187
- // Convert queues object to array if needed
188
- if (queuesData && typeof queuesData === 'object' && !Array.isArray(queuesData)) {
189
- this.queues = Object.entries(queuesData).map(([name, data]) => ({
190
- name,
191
- ...data
192
- }));
193
- } else {
194
- this.queues = queuesData || [];
195
- }
196
-
197
- this.counts.queues = this.queues.length;
198
-
199
- console.log('📋 Queues loaded:', this.queues.length);
200
- } catch (error) {
201
- console.error('Failed to load queues:', error);
202
- }
203
- },
204
-
205
- async loadWorkers() {
206
- if (!window.tasksAPI) return;
207
-
208
- try {
209
- const response = await window.tasksAPI.tasksApiWorkersListRetrieve();
210
- const data = response?.data || response || {};
211
-
212
- this.workers = data.workers || [];
213
- this.counts.workers = data.active_count || this.workers.length;
214
-
215
- // Update stats.workers for overview display
216
- this.stats.workers = this.counts.workers;
217
-
218
- console.log('👷 Workers loaded:', this.workers.length, 'Active:', this.counts.workers);
219
- } catch (error) {
220
- console.error('Failed to load workers:', error);
221
- }
222
- },
223
-
224
- async loadTasks(page = 1) {
225
- if (!window.tasksAPI) return;
226
-
227
- try {
228
- // TODO: Pass page parameter to API when backend supports it
229
- const response = await window.tasksAPI.tasksApiTasksListRetrieve();
230
- const data = response?.data || response || {};
231
-
232
- this.tasks = data.tasks || [];
233
-
234
- // Update pagination info
235
- if (data.pagination) {
236
- this.pagination = {
237
- page: data.pagination.page || 1,
238
- page_size: data.pagination.page_size || 20,
239
- total_pages: data.pagination.total_pages || 1,
240
- total_count: data.pagination.total_count || this.tasks.length,
241
- has_next: data.pagination.has_next || false,
242
- has_previous: data.pagination.has_previous || false
243
- };
244
- }
245
-
246
- this.counts.tasks = this.pagination.total_count;
247
-
248
- console.log('📝 Tasks loaded:', this.tasks.length, 'Total:', this.pagination.total_count);
249
- } catch (error) {
250
- console.error('Failed to load tasks:', error);
251
- }
252
- },
253
-
254
- // Pagination methods
255
- nextPage() {
256
- if (this.pagination.has_next) {
257
- this.loadTasks(this.pagination.page + 1);
258
- }
259
- },
260
-
261
- previousPage() {
262
- if (this.pagination.has_previous) {
263
- this.loadTasks(this.pagination.page - 1);
264
- }
265
- },
266
-
267
- goToPage(page) {
268
- if (page >= 1 && page <= this.pagination.total_pages) {
269
- this.loadTasks(page);
270
- }
271
- },
272
-
273
- applyFilters() {
274
- console.log('🔍 Applying filters:', this.filters);
275
- // The filteredTasks computed property will automatically update
276
- },
277
-
278
- toggleAutoRefresh() {
279
- this.autoRefresh = !this.autoRefresh;
280
-
281
- if (this.autoRefresh) {
282
- this.startAutoRefresh();
283
- console.log('✅ Auto-refresh enabled');
284
- } else {
285
- this.stopAutoRefresh();
286
- console.log('⏸️ Auto-refresh disabled');
287
- }
288
- },
289
-
290
- startAutoRefresh() {
291
- // Clear existing interval
292
- this.stopAutoRefresh();
293
-
294
- // Set new interval (refresh every 5 seconds)
295
- this.autoRefreshInterval = setInterval(() => {
296
- console.log('🔄 Auto-refresh triggered');
297
- this.loadDashboardData();
298
- }, 5000);
299
- },
300
-
301
- stopAutoRefresh() {
302
- if (this.autoRefreshInterval) {
303
- clearInterval(this.autoRefreshInterval);
304
- this.autoRefreshInterval = null;
305
- }
306
- },
307
-
308
- updateLastUpdateTime() {
309
- const now = new Date();
310
- this.lastUpdateTime = now.toLocaleTimeString('en-US', {
311
- hour12: false,
312
- hour: '2-digit',
313
- minute: '2-digit',
314
- second: '2-digit'
315
- });
316
- },
317
-
318
- onTabChange(tab) {
319
- console.log(`🔄 Switched to ${tab} tab`);
320
-
321
- // Load data for specific tab if not loaded
322
- switch (tab) {
323
- case 'overview':
324
- if (Object.keys(this.stats).length === 0) {
325
- this.loadOverview();
326
- }
327
- break;
328
- case 'queues':
329
- if (this.queues.length === 0) {
330
- this.loadQueues();
331
- }
332
- break;
333
- case 'workers':
334
- if (this.workers.length === 0) {
335
- this.loadWorkers();
336
- }
337
- break;
338
- case 'tasks':
339
- if (this.tasks.length === 0) {
340
- this.loadTasks();
341
- }
342
- break;
343
- }
344
- },
345
-
346
- // Task management methods
347
- async clearAllTasks() {
348
- if (!confirm('Are you sure you want to clear all tasks?')) {
349
- return;
350
- }
351
-
352
- try {
353
- this.loading = true;
354
- this.showActionMessage('Clearing all tasks...', 'info');
355
- await window.tasksAPI.tasksApiClearCreate({});
356
- await this.loadTasks();
357
-
358
- this.showActionMessage('All tasks cleared successfully', 'success');
359
-
360
- if (window.showNotification) {
361
- window.showNotification('All tasks cleared successfully', 'success');
362
- }
363
-
364
- console.log('✅ All tasks cleared');
365
- } catch (error) {
366
- console.error('❌ Failed to clear tasks:', error);
367
- this.showActionMessage('Failed to clear tasks: ' + error.message, 'error');
368
-
369
- if (window.showNotification) {
370
- window.showNotification('Failed to clear tasks: ' + error.message, 'error');
371
- }
372
- } finally {
373
- this.loading = false;
374
- }
375
- },
376
-
377
- async clearAllQueues() {
378
- if (!confirm('Are you sure you want to clear all queues?')) {
379
- return;
380
- }
381
-
382
- try {
383
- this.loading = true;
384
- this.showActionMessage('Clearing all queues...', 'info');
385
- // Assuming there's an API endpoint for this
386
- await window.tasksAPI.tasksApiClearQueuesCreate({});
387
- await this.loadQueues();
388
-
389
- this.showActionMessage('All queues cleared successfully', 'success');
390
-
391
- if (window.showNotification) {
392
- window.showNotification('All queues cleared successfully', 'success');
393
- }
394
-
395
- console.log('✅ All queues cleared');
396
- } catch (error) {
397
- console.error('❌ Failed to clear queues:', error);
398
- this.showActionMessage('Failed to clear queues: ' + error.message, 'error');
399
-
400
- if (window.showNotification) {
401
- window.showNotification('Failed to clear queues: ' + error.message, 'error');
402
- }
403
- } finally {
404
- this.loading = false;
405
- }
406
- },
407
-
408
- async purgeFailedTasks() {
409
- if (!confirm('Are you sure you want to purge all failed tasks?')) {
410
- return;
411
- }
412
-
413
- try {
414
- this.loading = true;
415
- this.showActionMessage('Purging failed tasks...', 'info');
416
- // Assuming there's an API endpoint for this
417
- await window.tasksAPI.tasksApiPurgeFailedCreate({});
418
- await this.loadTasks();
419
-
420
- this.showActionMessage('Failed tasks purged successfully', 'success');
421
-
422
- if (window.showNotification) {
423
- window.showNotification('Failed tasks purged successfully', 'success');
424
- }
425
-
426
- console.log('✅ Failed tasks purged');
427
- } catch (error) {
428
- console.error('❌ Failed to purge failed tasks:', error);
429
- this.showActionMessage('Failed to purge failed tasks: ' + error.message, 'error');
430
-
431
- if (window.showNotification) {
432
- window.showNotification('Failed to purge failed tasks: ' + error.message, 'error');
433
- }
434
- } finally {
435
- this.loading = false;
436
- }
437
- },
438
-
439
- async simulateTasks(count = 5) {
440
- try {
441
- this.loading = true;
442
- this.showActionMessage(`Simulating ${count} tasks...`, 'info');
443
- await window.tasksAPI.tasksApiSimulateCreate({
444
- count: count,
445
- queue: 'default',
446
- task_type: 'test'
447
- });
448
- await this.loadTasks();
449
-
450
- this.showActionMessage(`Simulated ${count} tasks successfully`, 'success');
451
-
452
- if (window.showNotification) {
453
- window.showNotification(`Simulated ${count} tasks successfully`, 'success');
454
- }
455
-
456
- console.log(`✅ Simulated ${count} tasks`);
457
- } catch (error) {
458
- console.error('❌ Failed to simulate tasks:', error);
459
- this.showActionMessage('Failed to simulate tasks: ' + error.message, 'error');
460
-
461
- if (window.showNotification) {
462
- window.showNotification('Failed to simulate tasks: ' + error.message, 'error');
463
- }
464
- } finally {
465
- this.loading = false;
466
- }
467
- },
468
-
469
- showActionMessage(message, type = 'info') {
470
- this.actionMessage = message;
471
- this.actionType = type;
472
-
473
- // Auto-hide after 5 seconds
474
- setTimeout(() => {
475
- this.actionMessage = '';
476
- }, 5000);
477
- },
478
-
479
- async startWorkers() {
480
- try {
481
- this.loading = true;
482
- this.showActionMessage('Starting workers...', 'info');
483
- await window.tasksAPI.tasksApiWorkersManageCreate({ action: 'start' });
484
- await this.loadWorkers();
485
-
486
- this.showActionMessage('Workers started successfully', 'success');
487
-
488
- if (window.showNotification) {
489
- window.showNotification('Workers started successfully', 'success');
490
- }
491
-
492
- console.log('✅ Workers started');
493
- } catch (error) {
494
- console.error('❌ Failed to start workers:', error);
495
- this.showActionMessage('Failed to start workers: ' + error.message, 'error');
496
-
497
- if (window.showNotification) {
498
- window.showNotification('Failed to start workers: ' + error.message, 'error');
499
- }
500
- } finally {
501
- this.loading = false;
502
- }
503
- },
504
-
505
- async stopWorkers() {
506
- if (!confirm('Are you sure you want to stop all workers?')) {
507
- return;
508
- }
509
-
510
- try {
511
- this.loading = true;
512
- this.showActionMessage('Stopping workers...', 'info');
513
- await window.tasksAPI.tasksApiWorkersManageCreate({ action: 'stop' });
514
- await this.loadWorkers();
515
-
516
- this.showActionMessage('Workers stopped successfully', 'success');
517
-
518
- if (window.showNotification) {
519
- window.showNotification('Workers stopped successfully', 'success');
520
- }
521
-
522
- console.log('✅ Workers stopped');
523
- } catch (error) {
524
- console.error('❌ Failed to stop workers:', error);
525
- this.showActionMessage('Failed to stop workers: ' + error.message, 'error');
526
-
527
- if (window.showNotification) {
528
- window.showNotification('Failed to stop workers: ' + error.message, 'error');
529
- }
530
- } finally {
531
- this.loading = false;
532
- }
533
- },
534
-
535
- // Task status helpers
536
- getStatusColor(status) {
537
- const colors = {
538
- 'pending': 'yellow',
539
- 'running': 'blue',
540
- 'completed': 'green',
541
- 'failed': 'red'
542
- };
543
- return colors[status] || 'gray';
544
- },
545
-
546
- formatDuration(ms) {
547
- if (!ms) return '-';
548
-
549
- if (ms < 1000) {
550
- return `${ms}ms`;
551
- } else if (ms < 60000) {
552
- return `${(ms / 1000).toFixed(1)}s`;
553
- } else {
554
- return `${(ms / 60000).toFixed(1)}m`;
555
- }
556
- },
557
-
558
- formatDate(dateString) {
559
- if (!dateString) return '-';
560
-
561
- try {
562
- const date = new Date(dateString);
563
- return date.toLocaleString('en-US', {
564
- month: 'short',
565
- day: 'numeric',
566
- hour: '2-digit',
567
- minute: '2-digit',
568
- second: '2-digit'
569
- });
570
- } catch (error) {
571
- return dateString;
572
- }
573
- },
574
-
575
- // Task action methods
576
- async viewTaskDetails(task) {
577
- console.log('View task details:', task);
578
- this.selectedTask = task;
579
- this.showTaskModal = true;
580
- },
581
-
582
- closeTaskModal() {
583
- this.showTaskModal = false;
584
- // Clear selected task after transition
585
- setTimeout(() => {
586
- this.selectedTask = null;
587
- }, 300);
588
- },
589
-
590
- async retryTask(task) {
591
- // TODO: Implement retry task endpoint in backend API
592
- this.showActionMessage('Retry task feature is not yet implemented', 'error');
593
-
594
- if (window.showNotification) {
595
- window.showNotification('Retry task feature is not yet implemented', 'error');
596
- }
597
-
598
- console.warn('⚠️ Retry task endpoint not implemented in API');
599
- },
600
-
601
- async deleteTask(task) {
602
- // TODO: Implement delete task endpoint in backend API
603
- this.showActionMessage('Delete task feature is not yet implemented', 'error');
604
-
605
- if (window.showNotification) {
606
- window.showNotification('Delete task feature is not yet implemented', 'error');
607
- }
608
-
609
- console.warn('⚠️ Delete task endpoint not implemented in API');
610
- },
611
-
612
- // Footer action methods
613
- async clearCompletedTasks() {
614
- // TODO: Implement clear completed tasks endpoint in backend API
615
- this.showActionMessage('Clear completed tasks feature is not yet implemented', 'error');
616
-
617
- if (window.showNotification) {
618
- window.showNotification('Clear completed tasks feature is not yet implemented', 'error');
619
- }
620
-
621
- console.warn('⚠️ Clear completed tasks endpoint not implemented in API');
622
- },
623
-
624
- async exportTasksCSV() {
625
- try {
626
- this.showActionMessage('Exporting tasks to CSV...', 'info');
627
-
628
- // Simple CSV export implementation
629
- const headers = ['ID', 'Name', 'Status', 'Queue', 'Duration', 'Created', 'Updated'];
630
- const rows = this.tasks.map(task => [
631
- task.task_id || task.id,
632
- task.name,
633
- task.status,
634
- task.queue || 'default',
635
- task.duration || '',
636
- task.created_at || '',
637
- task.updated_at || ''
638
- ]);
639
-
640
- const csvContent = [
641
- headers.join(','),
642
- ...rows.map(row => row.map(cell => `"${cell}"`).join(','))
643
- ].join('\n');
644
-
645
- // Create blob and download
646
- const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
647
- const link = document.createElement('a');
648
- const url = URL.createObjectURL(blob);
649
-
650
- link.setAttribute('href', url);
651
- link.setAttribute('download', `tasks_export_${new Date().toISOString().split('T')[0]}.csv`);
652
- link.style.visibility = 'hidden';
653
-
654
- document.body.appendChild(link);
655
- link.click();
656
- document.body.removeChild(link);
657
-
658
- this.showActionMessage('Tasks exported successfully', 'success');
659
-
660
- if (window.showNotification) {
661
- window.showNotification('Tasks exported to CSV', 'success');
662
- }
663
-
664
- console.log('✅ Tasks exported to CSV');
665
- } catch (error) {
666
- console.error('❌ Failed to export tasks:', error);
667
- this.showActionMessage('Failed to export tasks: ' + error.message, 'error');
668
-
669
- if (window.showNotification) {
670
- window.showNotification('Failed to export tasks: ' + error.message, 'error');
671
- }
672
- }
673
- }
674
- }));
675
- });
676
-
677
- // Add global helper functions for Alpine.js templates
678
- window.dashboardHelpers = {
679
- formatDuration: (ms) => {
680
- if (!ms) return '-';
681
-
682
- if (ms < 1000) {
683
- return `${ms}ms`;
684
- } else if (ms < 60000) {
685
- return `${(ms / 1000).toFixed(1)}s`;
686
- } else {
687
- return `${(ms / 60000).toFixed(1)}m`;
688
- }
689
- },
690
-
691
- formatDate: (dateString) => {
692
- if (!dateString) return '-';
693
-
694
- try {
695
- const date = new Date(dateString);
696
- return date.toLocaleString('en-US', {
697
- month: 'short',
698
- day: 'numeric',
699
- hour: '2-digit',
700
- minute: '2-digit',
701
- second: '2-digit'
702
- });
703
- } catch (error) {
704
- return dateString;
705
- }
706
- },
707
-
708
- getStatusBadgeClass: (status) => {
709
- const classes = {
710
- 'pending': 'bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200',
711
- 'running': 'bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200',
712
- 'completed': 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200',
713
- 'failed': 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200'
714
- };
715
- return classes[status] || 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200';
716
- }
717
- };
718
-
719
- // Cleanup on page unload
720
- window.addEventListener('beforeunload', () => {
721
- console.log('🧹 Cleaning up dashboard...');
722
- // Alpine.js will handle cleanup automatically
723
- });
724
-
725
- console.log('✅ Dashboard Alpine.js extensions loaded');