django-cfg 1.1.53__py3-none-any.whl → 1.1.55__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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/migrations/0004_delete_twilioresponse.py +16 -0
- django_cfg/apps/tasks/admin.py +5 -6
- django_cfg/apps/tasks/serializers.py +82 -0
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +269 -0
- django_cfg/apps/tasks/static/tasks/js/api.js +144 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +614 -0
- django_cfg/apps/tasks/static/tasks/js/modals.js +452 -0
- django_cfg/apps/tasks/static/tasks/js/notifications.js +144 -0
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +454 -0
- django_cfg/apps/tasks/static/tasks/js/theme.js +77 -0
- django_cfg/apps/tasks/templates/tasks/base.html +96 -0
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +85 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +53 -0
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +22 -0
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/status_cards.html +50 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +27 -0
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +103 -0
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +32 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +29 -0
- django_cfg/apps/tasks/templates/tasks/dashboard.html +22 -442
- django_cfg/apps/tasks/urls.py +10 -8
- django_cfg/apps/tasks/views.py +410 -172
- django_cfg/archive/django_sample.zip +0 -0
- django_cfg/core/generation.py +26 -2
- django_cfg/management/commands/clear_constance.py +200 -0
- django_cfg/management/commands/rundramatiq.py +6 -3
- django_cfg/models/constance.py +29 -23
- django_cfg/modules/base.py +19 -1
- django_cfg/modules/django_llm/README.md +296 -432
- django_cfg/modules/django_llm/__init__.py +5 -9
- django_cfg/modules/django_llm/llm/client.py +195 -176
- django_cfg/modules/django_llm/llm/costs.py +188 -0
- django_cfg/modules/django_llm/llm/extractor.py +85 -0
- django_cfg/modules/django_llm/llm/tokenizer.py +83 -0
- django_cfg/modules/django_tasks.py +282 -53
- django_cfg/routers.py +51 -16
- django_cfg/utils/smart_defaults.py +17 -1
- {django_cfg-1.1.53.dist-info → django_cfg-1.1.55.dist-info}/METADATA +6 -1
- {django_cfg-1.1.53.dist-info → django_cfg-1.1.55.dist-info}/RECORD +44 -26
- django_cfg/examples/README_NGROK.md +0 -186
- django_cfg/examples/README_NGROK_ENV.md +0 -194
- django_cfg/examples/ngrok_env_example.py +0 -155
- django_cfg/examples/ngrok_example.py +0 -75
- django_cfg/modules/django_llm/service.py +0 -423
- {django_cfg-1.1.53.dist-info → django_cfg-1.1.55.dist-info}/WHEEL +0 -0
- {django_cfg-1.1.53.dist-info → django_cfg-1.1.55.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.1.53.dist-info → django_cfg-1.1.55.dist-info}/licenses/LICENSE +0 -0
django_cfg/__init__.py
CHANGED
@@ -38,7 +38,7 @@ default_app_config = "django_cfg.apps.DjangoCfgConfig"
|
|
38
38
|
from typing import TYPE_CHECKING
|
39
39
|
|
40
40
|
# Version information
|
41
|
-
__version__ = "1.1.
|
41
|
+
__version__ = "1.1.55"
|
42
42
|
__author__ = "Unrealos Team"
|
43
43
|
__email__ = "info@unrealos.com"
|
44
44
|
__license__ = "MIT"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-16 18:57
|
2
|
+
|
3
|
+
from django.db import migrations
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('django_cfg_accounts', '0003_twilioresponse'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.DeleteModel(
|
14
|
+
name='TwilioResponse',
|
15
|
+
),
|
16
|
+
]
|
django_cfg/apps/tasks/admin.py
CHANGED
@@ -10,6 +10,7 @@ import subprocess
|
|
10
10
|
import sys
|
11
11
|
from typing import Dict, Any
|
12
12
|
|
13
|
+
from django.db.models import Count
|
13
14
|
from django.contrib import admin
|
14
15
|
from django.contrib.admin.views.main import ChangeList
|
15
16
|
from django.http import JsonResponse
|
@@ -226,8 +227,8 @@ class TaskQueueAdmin(ModelAdmin):
|
|
226
227
|
queues_info = {}
|
227
228
|
config = self.tasks_service.config
|
228
229
|
|
229
|
-
if config and config.queues:
|
230
|
-
for queue_name in config.queues:
|
230
|
+
if config and config.dramatiq and config.dramatiq.queues:
|
231
|
+
for queue_name in config.dramatiq.queues:
|
231
232
|
queue_key = f"dramatiq:default.DQ.{queue_name}"
|
232
233
|
queue_length = redis_client.llen(queue_key)
|
233
234
|
|
@@ -267,17 +268,15 @@ class TaskQueueAdmin(ModelAdmin):
|
|
267
268
|
if not Task:
|
268
269
|
return {'error': 'django_dramatiq not available'}
|
269
270
|
|
270
|
-
# Get task counts by status
|
271
|
-
from django.db.models import Count
|
272
271
|
|
273
|
-
stats = Task.
|
272
|
+
stats = Task.tasks.aggregate(
|
274
273
|
total=Count('id'),
|
275
274
|
# Add more aggregations as needed
|
276
275
|
)
|
277
276
|
|
278
277
|
# Get recent tasks
|
279
278
|
recent_tasks = list(
|
280
|
-
Task.
|
279
|
+
Task.tasks.order_by('-created_at')[:10]
|
281
280
|
.values('actor_name', 'status', 'created_at', 'updated_at')
|
282
281
|
)
|
283
282
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
"""
|
2
|
+
Serializers for Django CFG Tasks app.
|
3
|
+
|
4
|
+
Provides DRF serializers for task management API endpoints.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from rest_framework import serializers
|
8
|
+
from typing import Dict, Any
|
9
|
+
|
10
|
+
|
11
|
+
class QueueStatusSerializer(serializers.Serializer):
|
12
|
+
"""Serializer for queue status data."""
|
13
|
+
|
14
|
+
queues = serializers.DictField(
|
15
|
+
child=serializers.DictField(
|
16
|
+
child=serializers.IntegerField()
|
17
|
+
),
|
18
|
+
help_text="Queue information with pending/failed counts"
|
19
|
+
)
|
20
|
+
workers = serializers.IntegerField(help_text="Number of active workers")
|
21
|
+
redis_connected = serializers.BooleanField(help_text="Redis connection status")
|
22
|
+
timestamp = serializers.CharField(help_text="Current timestamp")
|
23
|
+
error = serializers.CharField(required=False, help_text="Error message if any")
|
24
|
+
|
25
|
+
|
26
|
+
class TaskStatisticsSerializer(serializers.Serializer):
|
27
|
+
"""Serializer for task statistics data."""
|
28
|
+
|
29
|
+
statistics = serializers.DictField(
|
30
|
+
child=serializers.IntegerField(),
|
31
|
+
help_text="Task count statistics"
|
32
|
+
)
|
33
|
+
recent_tasks = serializers.ListField(
|
34
|
+
child=serializers.DictField(),
|
35
|
+
help_text="List of recent tasks"
|
36
|
+
)
|
37
|
+
timestamp = serializers.CharField(help_text="Current timestamp")
|
38
|
+
error = serializers.CharField(required=False, help_text="Error message if any")
|
39
|
+
|
40
|
+
|
41
|
+
class WorkerActionSerializer(serializers.Serializer):
|
42
|
+
"""Serializer for worker management actions."""
|
43
|
+
|
44
|
+
action = serializers.ChoiceField(
|
45
|
+
choices=['start', 'stop', 'restart'],
|
46
|
+
help_text="Action to perform on workers"
|
47
|
+
)
|
48
|
+
processes = serializers.IntegerField(
|
49
|
+
default=1,
|
50
|
+
min_value=1,
|
51
|
+
max_value=10,
|
52
|
+
help_text="Number of worker processes"
|
53
|
+
)
|
54
|
+
threads = serializers.IntegerField(
|
55
|
+
default=2,
|
56
|
+
min_value=1,
|
57
|
+
max_value=20,
|
58
|
+
help_text="Number of threads per process"
|
59
|
+
)
|
60
|
+
|
61
|
+
|
62
|
+
class QueueActionSerializer(serializers.Serializer):
|
63
|
+
"""Serializer for queue management actions."""
|
64
|
+
|
65
|
+
action = serializers.ChoiceField(
|
66
|
+
choices=['clear', 'clear_all', 'purge', 'purge_failed', 'flush'],
|
67
|
+
help_text="Action to perform on queues"
|
68
|
+
)
|
69
|
+
queue_names = serializers.ListField(
|
70
|
+
child=serializers.CharField(),
|
71
|
+
required=False,
|
72
|
+
help_text="Specific queues to target (empty = all queues)"
|
73
|
+
)
|
74
|
+
|
75
|
+
|
76
|
+
class APIResponseSerializer(serializers.Serializer):
|
77
|
+
"""Standard API response serializer."""
|
78
|
+
|
79
|
+
success = serializers.BooleanField(help_text="Operation success status")
|
80
|
+
message = serializers.CharField(required=False, help_text="Success message")
|
81
|
+
error = serializers.CharField(required=False, help_text="Error message")
|
82
|
+
data = serializers.DictField(required=False, help_text="Response data")
|
@@ -0,0 +1,269 @@
|
|
1
|
+
/**
|
2
|
+
* Dashboard Custom Styles
|
3
|
+
* Additional styles for the Dramatiq Tasks Dashboard
|
4
|
+
*/
|
5
|
+
|
6
|
+
/* Custom scrollbar for dark mode */
|
7
|
+
::-webkit-scrollbar {
|
8
|
+
width: 8px;
|
9
|
+
height: 8px;
|
10
|
+
}
|
11
|
+
|
12
|
+
::-webkit-scrollbar-track {
|
13
|
+
background: transparent;
|
14
|
+
}
|
15
|
+
|
16
|
+
::-webkit-scrollbar-thumb {
|
17
|
+
background: rgba(156, 163, 175, 0.5);
|
18
|
+
border-radius: 4px;
|
19
|
+
}
|
20
|
+
|
21
|
+
::-webkit-scrollbar-thumb:hover {
|
22
|
+
background: rgba(156, 163, 175, 0.7);
|
23
|
+
}
|
24
|
+
|
25
|
+
.dark ::-webkit-scrollbar-thumb {
|
26
|
+
background: rgba(75, 85, 99, 0.5);
|
27
|
+
}
|
28
|
+
|
29
|
+
.dark ::-webkit-scrollbar-thumb:hover {
|
30
|
+
background: rgba(75, 85, 99, 0.7);
|
31
|
+
}
|
32
|
+
|
33
|
+
/* Tab transitions */
|
34
|
+
.tab-button {
|
35
|
+
transition: all 0.2s ease-in-out;
|
36
|
+
}
|
37
|
+
|
38
|
+
.tab-panel {
|
39
|
+
transition: opacity 0.2s ease-in-out;
|
40
|
+
}
|
41
|
+
|
42
|
+
.tab-panel.hidden {
|
43
|
+
opacity: 0;
|
44
|
+
}
|
45
|
+
|
46
|
+
.tab-panel.active {
|
47
|
+
opacity: 1;
|
48
|
+
}
|
49
|
+
|
50
|
+
/* Loading animations */
|
51
|
+
@keyframes pulse {
|
52
|
+
0%, 100% {
|
53
|
+
opacity: 1;
|
54
|
+
}
|
55
|
+
50% {
|
56
|
+
opacity: 0.5;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
.animate-pulse {
|
61
|
+
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
62
|
+
}
|
63
|
+
|
64
|
+
/* Status indicators */
|
65
|
+
.status-indicator {
|
66
|
+
position: relative;
|
67
|
+
display: inline-block;
|
68
|
+
}
|
69
|
+
|
70
|
+
.status-indicator::before {
|
71
|
+
content: '';
|
72
|
+
position: absolute;
|
73
|
+
top: 0;
|
74
|
+
right: 0;
|
75
|
+
width: 8px;
|
76
|
+
height: 8px;
|
77
|
+
border-radius: 50%;
|
78
|
+
border: 2px solid white;
|
79
|
+
}
|
80
|
+
|
81
|
+
.status-indicator.online::before {
|
82
|
+
background-color: #10b981;
|
83
|
+
}
|
84
|
+
|
85
|
+
.status-indicator.offline::before {
|
86
|
+
background-color: #ef4444;
|
87
|
+
}
|
88
|
+
|
89
|
+
.status-indicator.warning::before {
|
90
|
+
background-color: #f59e0b;
|
91
|
+
}
|
92
|
+
|
93
|
+
/* Card hover effects */
|
94
|
+
.card-hover {
|
95
|
+
transition: all 0.2s ease-in-out;
|
96
|
+
}
|
97
|
+
|
98
|
+
.card-hover:hover {
|
99
|
+
transform: translateY(-2px);
|
100
|
+
box-shadow: 0 10px 25px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
101
|
+
}
|
102
|
+
|
103
|
+
.dark .card-hover:hover {
|
104
|
+
box-shadow: 0 10px 25px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2);
|
105
|
+
}
|
106
|
+
|
107
|
+
/* Button loading state */
|
108
|
+
.btn-loading {
|
109
|
+
position: relative;
|
110
|
+
pointer-events: none;
|
111
|
+
}
|
112
|
+
|
113
|
+
.btn-loading::after {
|
114
|
+
content: '';
|
115
|
+
position: absolute;
|
116
|
+
top: 50%;
|
117
|
+
left: 50%;
|
118
|
+
width: 16px;
|
119
|
+
height: 16px;
|
120
|
+
margin: -8px 0 0 -8px;
|
121
|
+
border: 2px solid transparent;
|
122
|
+
border-top: 2px solid currentColor;
|
123
|
+
border-radius: 50%;
|
124
|
+
animation: spin 1s linear infinite;
|
125
|
+
}
|
126
|
+
|
127
|
+
@keyframes spin {
|
128
|
+
0% {
|
129
|
+
transform: rotate(0deg);
|
130
|
+
}
|
131
|
+
100% {
|
132
|
+
transform: rotate(360deg);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
/* Modal backdrop blur */
|
137
|
+
.modal-backdrop {
|
138
|
+
backdrop-filter: blur(4px);
|
139
|
+
-webkit-backdrop-filter: blur(4px);
|
140
|
+
}
|
141
|
+
|
142
|
+
/* Custom focus styles */
|
143
|
+
.focus-ring:focus {
|
144
|
+
outline: 2px solid transparent;
|
145
|
+
outline-offset: 2px;
|
146
|
+
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5);
|
147
|
+
}
|
148
|
+
|
149
|
+
.dark .focus-ring:focus {
|
150
|
+
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.5);
|
151
|
+
}
|
152
|
+
|
153
|
+
/* Progress bars */
|
154
|
+
.progress-bar {
|
155
|
+
position: relative;
|
156
|
+
overflow: hidden;
|
157
|
+
background-color: #e5e7eb;
|
158
|
+
border-radius: 0.25rem;
|
159
|
+
height: 0.5rem;
|
160
|
+
}
|
161
|
+
|
162
|
+
.dark .progress-bar {
|
163
|
+
background-color: #374151;
|
164
|
+
}
|
165
|
+
|
166
|
+
.progress-bar-fill {
|
167
|
+
height: 100%;
|
168
|
+
background-color: #3b82f6;
|
169
|
+
transition: width 0.3s ease-in-out;
|
170
|
+
}
|
171
|
+
|
172
|
+
.progress-bar-fill.success {
|
173
|
+
background-color: #10b981;
|
174
|
+
}
|
175
|
+
|
176
|
+
.progress-bar-fill.warning {
|
177
|
+
background-color: #f59e0b;
|
178
|
+
}
|
179
|
+
|
180
|
+
.progress-bar-fill.error {
|
181
|
+
background-color: #ef4444;
|
182
|
+
}
|
183
|
+
|
184
|
+
/* Tooltip styles */
|
185
|
+
.tooltip {
|
186
|
+
position: relative;
|
187
|
+
}
|
188
|
+
|
189
|
+
.tooltip::before {
|
190
|
+
content: attr(data-tooltip);
|
191
|
+
position: absolute;
|
192
|
+
bottom: 100%;
|
193
|
+
left: 50%;
|
194
|
+
transform: translateX(-50%);
|
195
|
+
padding: 0.5rem;
|
196
|
+
background-color: #1f2937;
|
197
|
+
color: white;
|
198
|
+
font-size: 0.75rem;
|
199
|
+
border-radius: 0.25rem;
|
200
|
+
white-space: nowrap;
|
201
|
+
opacity: 0;
|
202
|
+
pointer-events: none;
|
203
|
+
transition: opacity 0.2s ease-in-out;
|
204
|
+
z-index: 1000;
|
205
|
+
}
|
206
|
+
|
207
|
+
.tooltip:hover::before {
|
208
|
+
opacity: 1;
|
209
|
+
}
|
210
|
+
|
211
|
+
/* Responsive adjustments */
|
212
|
+
@media (max-width: 768px) {
|
213
|
+
.tab-button {
|
214
|
+
padding: 0.5rem 0.25rem;
|
215
|
+
font-size: 0.75rem;
|
216
|
+
}
|
217
|
+
|
218
|
+
.tab-button .material-icons {
|
219
|
+
display: none;
|
220
|
+
}
|
221
|
+
|
222
|
+
.status-cards {
|
223
|
+
grid-template-columns: repeat(2, 1fr);
|
224
|
+
gap: 1rem;
|
225
|
+
}
|
226
|
+
|
227
|
+
.info-cards {
|
228
|
+
grid-template-columns: 1fr;
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
@media (max-width: 640px) {
|
233
|
+
.status-cards {
|
234
|
+
grid-template-columns: 1fr;
|
235
|
+
}
|
236
|
+
|
237
|
+
.tab-navigation {
|
238
|
+
overflow-x: auto;
|
239
|
+
scrollbar-width: none;
|
240
|
+
-ms-overflow-style: none;
|
241
|
+
}
|
242
|
+
|
243
|
+
.tab-navigation::-webkit-scrollbar {
|
244
|
+
display: none;
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
/* Print styles */
|
249
|
+
@media print {
|
250
|
+
.tab-navigation,
|
251
|
+
.modal-container,
|
252
|
+
button {
|
253
|
+
display: none !important;
|
254
|
+
}
|
255
|
+
|
256
|
+
.tab-panel {
|
257
|
+
display: block !important;
|
258
|
+
}
|
259
|
+
|
260
|
+
.bg-gray-50,
|
261
|
+
.dark\:bg-gray-900 {
|
262
|
+
background: white !important;
|
263
|
+
}
|
264
|
+
|
265
|
+
.text-gray-900,
|
266
|
+
.dark\:text-white {
|
267
|
+
color: black !important;
|
268
|
+
}
|
269
|
+
}
|
@@ -0,0 +1,144 @@
|
|
1
|
+
/**
|
2
|
+
* API Client for Dramatiq Tasks Dashboard
|
3
|
+
* Handles all API communication with the backend
|
4
|
+
*/
|
5
|
+
|
6
|
+
class TasksAPI {
|
7
|
+
constructor(baseUrl = '/cfg/tasks/api') {
|
8
|
+
this.baseUrl = baseUrl;
|
9
|
+
}
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Make an API request
|
13
|
+
* @param {string} endpoint - API endpoint
|
14
|
+
* @param {Object} options - Fetch options
|
15
|
+
* @returns {Promise<Object>} API response
|
16
|
+
*/
|
17
|
+
async request(endpoint, options = {}) {
|
18
|
+
const url = `${this.baseUrl}${endpoint}`;
|
19
|
+
const defaultOptions = {
|
20
|
+
headers: {
|
21
|
+
'Content-Type': 'application/json',
|
22
|
+
'X-Requested-With': 'XMLHttpRequest',
|
23
|
+
},
|
24
|
+
credentials: 'same-origin', // Include cookies for session authentication
|
25
|
+
};
|
26
|
+
|
27
|
+
// Add CSRF token if available
|
28
|
+
let csrfToken = document.querySelector('[name=csrfmiddlewaretoken]');
|
29
|
+
if (!csrfToken) {
|
30
|
+
// Try alternative selectors
|
31
|
+
csrfToken = document.querySelector('input[name="csrfmiddlewaretoken"]');
|
32
|
+
}
|
33
|
+
if (!csrfToken) {
|
34
|
+
// Try getting from cookie
|
35
|
+
const cookies = document.cookie.split(';');
|
36
|
+
for (let cookie of cookies) {
|
37
|
+
const [name, value] = cookie.trim().split('=');
|
38
|
+
if (name === 'csrftoken') {
|
39
|
+
defaultOptions.headers['X-CSRFToken'] = value;
|
40
|
+
break;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
} else {
|
44
|
+
defaultOptions.headers['X-CSRFToken'] = csrfToken.value;
|
45
|
+
}
|
46
|
+
|
47
|
+
try {
|
48
|
+
const response = await fetch(url, { ...defaultOptions, ...options });
|
49
|
+
|
50
|
+
if (!response.ok) {
|
51
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
52
|
+
}
|
53
|
+
|
54
|
+
return await response.json();
|
55
|
+
} catch (error) {
|
56
|
+
console.error('API request failed:', error);
|
57
|
+
throw error;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
/**
|
62
|
+
* Get queue status
|
63
|
+
* @returns {Promise<Object>} Queue status data
|
64
|
+
*/
|
65
|
+
async getQueueStatus() {
|
66
|
+
return this.request('/queues/status/');
|
67
|
+
}
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Get task statistics
|
71
|
+
* @returns {Promise<Object>} Task statistics data
|
72
|
+
*/
|
73
|
+
async getTaskStatistics() {
|
74
|
+
return this.request('/tasks/stats/');
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Get detailed task list
|
79
|
+
* @param {Object} params - Query parameters (status, queue, search, limit, offset)
|
80
|
+
* @returns {Promise<Object>} Task list
|
81
|
+
*/
|
82
|
+
async getTaskList(params = {}) {
|
83
|
+
const queryString = new URLSearchParams(params).toString();
|
84
|
+
const url = `/tasks/list/${queryString ? '?' + queryString : ''}`;
|
85
|
+
return this.request(url);
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Start workers
|
90
|
+
* @param {Object} config - Worker configuration
|
91
|
+
* @returns {Promise<Object>} Operation result
|
92
|
+
*/
|
93
|
+
async startWorkers(config = {}) {
|
94
|
+
return this.request('/workers/manage/', {
|
95
|
+
method: 'POST',
|
96
|
+
body: JSON.stringify({
|
97
|
+
action: 'start',
|
98
|
+
...config
|
99
|
+
})
|
100
|
+
});
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Stop workers
|
105
|
+
* @returns {Promise<Object>} Operation result
|
106
|
+
*/
|
107
|
+
async stopWorkers() {
|
108
|
+
return this.request('/workers/manage/', {
|
109
|
+
method: 'POST',
|
110
|
+
body: JSON.stringify({
|
111
|
+
action: 'stop'
|
112
|
+
})
|
113
|
+
});
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Clear all queues
|
118
|
+
* @returns {Promise<Object>} Operation result
|
119
|
+
*/
|
120
|
+
async clearQueues() {
|
121
|
+
return this.request('/queues/manage/', {
|
122
|
+
method: 'POST',
|
123
|
+
body: JSON.stringify({
|
124
|
+
action: 'clear_all'
|
125
|
+
})
|
126
|
+
});
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Purge failed tasks
|
131
|
+
* @returns {Promise<Object>} Operation result
|
132
|
+
*/
|
133
|
+
async purgeFailedTasks() {
|
134
|
+
return this.request('/queues/manage/', {
|
135
|
+
method: 'POST',
|
136
|
+
body: JSON.stringify({
|
137
|
+
action: 'purge_failed'
|
138
|
+
})
|
139
|
+
});
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
// Create global API instance
|
144
|
+
window.tasksAPI = new TasksAPI();
|