django-spire 0.23.5__py3-none-any.whl → 0.23.7__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_spire/consts.py +1 -1
- django_spire/contrib/progress/__init__.py +1 -3
- django_spire/contrib/progress/static/django_spire/js/contrib/progress/progress.js +56 -31
- {django_spire-0.23.5.dist-info → django_spire-0.23.7.dist-info}/METADATA +1 -1
- {django_spire-0.23.5.dist-info → django_spire-0.23.7.dist-info}/RECORD +8 -9
- django_spire/contrib/progress/views.py +0 -64
- {django_spire-0.23.5.dist-info → django_spire-0.23.7.dist-info}/WHEEL +0 -0
- {django_spire-0.23.5.dist-info → django_spire-0.23.7.dist-info}/licenses/LICENSE.md +0 -0
- {django_spire-0.23.5.dist-info → django_spire-0.23.7.dist-info}/top_level.txt +0 -0
django_spire/consts.py
CHANGED
|
@@ -4,7 +4,6 @@ from django_spire.contrib.progress.runner import TaskProgressUpdater
|
|
|
4
4
|
from django_spire.contrib.progress.states import TaskState, TrackerState
|
|
5
5
|
from django_spire.contrib.progress.task import ProgressMessages, Task, TaskResult
|
|
6
6
|
from django_spire.contrib.progress.tracker import ProgressTracker
|
|
7
|
-
from django_spire.contrib.progress.views import sse_stream_view
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
__all__ = [
|
|
@@ -16,6 +15,5 @@ __all__ = [
|
|
|
16
15
|
'TaskProgressUpdater',
|
|
17
16
|
'TaskResult',
|
|
18
17
|
'TaskState',
|
|
19
|
-
'TrackerState'
|
|
20
|
-
'sse_stream_view',
|
|
18
|
+
'TrackerState'
|
|
21
19
|
]
|
|
@@ -1,61 +1,86 @@
|
|
|
1
1
|
class ProgressStream {
|
|
2
2
|
constructor(url, config = {}) {
|
|
3
3
|
this.url = url;
|
|
4
|
-
this.
|
|
4
|
+
this.is_running = false;
|
|
5
|
+
this.poll_interval = null;
|
|
6
|
+
|
|
5
7
|
this.config = {
|
|
6
8
|
on_update: config.on_update || (() => {}),
|
|
7
9
|
on_complete: config.on_complete || (() => {}),
|
|
8
10
|
on_error: config.on_error || (() => {}),
|
|
9
11
|
redirect_on_complete: config.redirect_on_complete || null,
|
|
10
|
-
redirect_delay: config.redirect_delay || 1000
|
|
12
|
+
redirect_delay: config.redirect_delay || 1000,
|
|
13
|
+
poll_interval: config.poll_interval || 1000
|
|
11
14
|
};
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
start() {
|
|
15
|
-
|
|
17
|
+
async start() {
|
|
18
|
+
if (this.is_running) return;
|
|
19
|
+
|
|
20
|
+
this.is_running = true;
|
|
21
|
+
this._start_polling();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
stop() {
|
|
25
|
+
if (!this.is_running) return;
|
|
26
|
+
|
|
27
|
+
this.is_running = false;
|
|
28
|
+
|
|
29
|
+
if (this.poll_interval) {
|
|
30
|
+
clearInterval(this.poll_interval);
|
|
31
|
+
this.poll_interval = null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_start_polling() {
|
|
36
|
+
this._poll();
|
|
37
|
+
|
|
38
|
+
this.poll_interval = setInterval(() => {
|
|
39
|
+
if (this.is_running) {
|
|
40
|
+
this._poll();
|
|
41
|
+
}
|
|
42
|
+
}, this.config.poll_interval);
|
|
43
|
+
}
|
|
16
44
|
|
|
17
|
-
|
|
18
|
-
|
|
45
|
+
async _poll() {
|
|
46
|
+
try {
|
|
47
|
+
let response = await fetch(this.url, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'X-CSRFToken': get_cookie('csrftoken'),
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new Error(`HTTP ${response.status}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let data = await response.json();
|
|
19
59
|
|
|
20
60
|
this.config.on_update(data);
|
|
21
61
|
|
|
22
62
|
if (data.step === 'error') {
|
|
23
63
|
this.config.on_error(data);
|
|
24
64
|
this.stop();
|
|
25
|
-
|
|
26
65
|
return;
|
|
27
66
|
}
|
|
28
67
|
|
|
29
68
|
if (data.progress >= 100) {
|
|
30
69
|
this.config.on_complete(data);
|
|
31
70
|
this.stop();
|
|
32
|
-
|
|
33
|
-
if (this.config.redirect_on_complete) {
|
|
34
|
-
setTimeout(() => {
|
|
35
|
-
window.location.href = this.config.redirect_on_complete;
|
|
36
|
-
}, this.config.redirect_delay);
|
|
37
|
-
}
|
|
71
|
+
this._redirect();
|
|
38
72
|
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
console.error('ProgressStream error:', error);
|
|
43
|
-
|
|
44
|
-
this.config.on_error({
|
|
45
|
-
step: 'error',
|
|
46
|
-
message: 'Connection error',
|
|
47
|
-
progress: 0
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
this.stop();
|
|
51
|
-
};
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.warn('Poll error:', error.message);
|
|
75
|
+
}
|
|
52
76
|
}
|
|
53
77
|
|
|
54
|
-
|
|
55
|
-
if (this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
78
|
+
_redirect() {
|
|
79
|
+
if (!this.config.redirect_on_complete) return;
|
|
80
|
+
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
window.location.href = this.config.redirect_on_complete;
|
|
83
|
+
}, this.config.redirect_delay);
|
|
59
84
|
}
|
|
60
85
|
}
|
|
61
86
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-spire
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.7
|
|
4
4
|
Summary: A project for Django Spire
|
|
5
5
|
Author-email: Brayden Carlson <braydenc@stratusadv.com>, Nathan Johnson <nathanj@stratusadv.com>
|
|
6
6
|
License: Copyright (c) 2024 Stratus Advanced Technologies and Contributors.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
django_spire/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
django_spire/conf.py,sha256=c5Hs-7lk9T15254tOasiQ2ZTFLQIVJof9_QJDfm1PAI,933
|
|
3
|
-
django_spire/consts.py,sha256=
|
|
3
|
+
django_spire/consts.py,sha256=ab54JzPcaJsVKbgkIP9oB2Dn-58eOdewXxUUZlbYeRw,171
|
|
4
4
|
django_spire/exceptions.py,sha256=L5ndRO5ftMmh0pHkO2z_NG3LSGZviJ-dDHNT73SzTNw,48
|
|
5
5
|
django_spire/settings.py,sha256=B4GPqBGt_dmkt0Ay0j-IP-SZ6mY44m2Ap5kVSON5YLA,1005
|
|
6
6
|
django_spire/urls.py,sha256=mKeZszb5U4iIGqddMb5Tt5fRC72U2wABEOi6mvOfEBU,656
|
|
@@ -348,16 +348,15 @@ django_spire/contrib/pagination/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TI
|
|
|
348
348
|
django_spire/contrib/pagination/templatetags/pagination_tags.py,sha256=xE3zTDJZDdDvWf6D7fMyg_Vi0PW37OA3aZxCjOHDp4I,1173
|
|
349
349
|
django_spire/contrib/performance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
350
350
|
django_spire/contrib/performance/decorators.py,sha256=xOjXX-3FVOEWqr2TTTqdh4lkIhmHTlROevOVgXDeyt8,507
|
|
351
|
-
django_spire/contrib/progress/__init__.py,sha256=
|
|
351
|
+
django_spire/contrib/progress/__init__.py,sha256=pvd6_7puMDWStjZqcwsWEulpeGupQPv2fladV1IiaXg,631
|
|
352
352
|
django_spire/contrib/progress/enums.py,sha256=nwyfKxQno_ghGGTbpK8lRO1cY7dCfbxnnsQ4cSbkXBw,194
|
|
353
353
|
django_spire/contrib/progress/mixins.py,sha256=V84LRtniFDLK2E5dKcSZNh-a1zTf9Ee7QXg1rDfoFHo,895
|
|
354
354
|
django_spire/contrib/progress/runner.py,sha256=3jSqpdk2MJ7HPNutwF43Hs81O0NlzX4E9gnVaenhXUs,4445
|
|
355
355
|
django_spire/contrib/progress/states.py,sha256=V7JU_nzpZN77TQFW0S51Gjil8xn8CKLKkAWDOpqzA8k,1908
|
|
356
356
|
django_spire/contrib/progress/task.py,sha256=4pMbzOsjRRNqPKNohh08D39DRFpC3QomTCH5IdqQS0A,780
|
|
357
357
|
django_spire/contrib/progress/tracker.py,sha256=xjGlEyKe5aiKW_KC8NKZ8F0BjQdFpLUqHz5Gr_C7jws,6490
|
|
358
|
-
django_spire/contrib/progress/views.py,sha256=CwJu-L09tTiCpsjVuqzvMEKVqp6-etLDi7L9ibmlq8U,1694
|
|
359
358
|
django_spire/contrib/progress/static/django_spire/css/contrib/progress/progress.css,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
360
|
-
django_spire/contrib/progress/static/django_spire/js/contrib/progress/progress.js,sha256=
|
|
359
|
+
django_spire/contrib/progress/static/django_spire/js/contrib/progress/progress.js,sha256=BeT52b8rHoBzk3tMpXX3bO3R-bDYTjyrEHjjc1AS2LQ,2228
|
|
361
360
|
django_spire/contrib/progress/templates/django_spire/contrib/progress/card/card.html,sha256=2Ajv0UBJEGwc4InVe69aLe2u4K56yh2JAuvO6uH24j8,3353
|
|
362
361
|
django_spire/contrib/progress/templates/django_spire/contrib/progress/modal/content.html,sha256=Qxer-q4GBC5h8onzno2NUlPrXluw_tO1kWlGComQ98E,5232
|
|
363
362
|
django_spire/contrib/queryset/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -1201,8 +1200,8 @@ django_spire/theme/urls/page_urls.py,sha256=S8nkKkgbhG3XHI3uMUL-piOjXIrRkuY2UlM_
|
|
|
1201
1200
|
django_spire/theme/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
1202
1201
|
django_spire/theme/views/json_views.py,sha256=PWwVTaty0BVGbj65L5cxex6JNhc-xVAI_rEYjbJWqEM,1893
|
|
1203
1202
|
django_spire/theme/views/page_views.py,sha256=WenjOa6Welpu3IMolY56ZwBjy4aK9hpbiMNuygjAl1A,3922
|
|
1204
|
-
django_spire-0.23.
|
|
1205
|
-
django_spire-0.23.
|
|
1206
|
-
django_spire-0.23.
|
|
1207
|
-
django_spire-0.23.
|
|
1208
|
-
django_spire-0.23.
|
|
1203
|
+
django_spire-0.23.7.dist-info/licenses/LICENSE.md,sha256=tlTbOtgKoy-xAQpUk9gPeh9O4oRXCOzoWdW3jJz0wnA,1091
|
|
1204
|
+
django_spire-0.23.7.dist-info/METADATA,sha256=NY3tdv-HT8M7IrLFbnRDxJtMCYxoanCmUPR7PDyy0Uk,5127
|
|
1205
|
+
django_spire-0.23.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
1206
|
+
django_spire-0.23.7.dist-info/top_level.txt,sha256=xf3QV1e--ONkVpgMDQE9iqjQ1Vg4--_6C8wmO-KxPHQ,13
|
|
1207
|
+
django_spire-0.23.7.dist-info/RECORD,,
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import time
|
|
5
|
-
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
7
|
-
|
|
8
|
-
from django.core.cache import cache
|
|
9
|
-
from django.http import StreamingHttpResponse
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from typing import Callable, Generator
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def sse_stream_view(
|
|
16
|
-
key: str,
|
|
17
|
-
interval: float = 0.5,
|
|
18
|
-
should_continue: Callable[[dict], bool] | None = None,
|
|
19
|
-
timeout: int = 300
|
|
20
|
-
) -> StreamingHttpResponse:
|
|
21
|
-
cache_key = f'progress_tracker_{key}'
|
|
22
|
-
|
|
23
|
-
def event_stream() -> Generator[str, None, None]:
|
|
24
|
-
previous_data = None
|
|
25
|
-
start_time = time.time()
|
|
26
|
-
last_heartbeat = time.time()
|
|
27
|
-
|
|
28
|
-
yield ': connected\n\n'
|
|
29
|
-
|
|
30
|
-
while True:
|
|
31
|
-
elapsed = time.time() - start_time
|
|
32
|
-
|
|
33
|
-
if elapsed > timeout:
|
|
34
|
-
yield f'data: {json.dumps({"step": "error", "message": "Timeout", "progress": 0})}\n\n'
|
|
35
|
-
break
|
|
36
|
-
|
|
37
|
-
data = cache.get(cache_key)
|
|
38
|
-
|
|
39
|
-
if data and data != previous_data:
|
|
40
|
-
yield f'data: {json.dumps(data)}\n\n'
|
|
41
|
-
previous_data = data
|
|
42
|
-
last_heartbeat = time.time()
|
|
43
|
-
|
|
44
|
-
if should_continue and not should_continue(data):
|
|
45
|
-
break
|
|
46
|
-
|
|
47
|
-
if data.get('progress', 0) >= 100 or data.get('step') == 'error':
|
|
48
|
-
break
|
|
49
|
-
|
|
50
|
-
if time.time() - last_heartbeat > 10:
|
|
51
|
-
yield ': heartbeat\n\n'
|
|
52
|
-
last_heartbeat = time.time()
|
|
53
|
-
|
|
54
|
-
time.sleep(interval)
|
|
55
|
-
|
|
56
|
-
response = StreamingHttpResponse(
|
|
57
|
-
event_stream(),
|
|
58
|
-
content_type='text/event-stream'
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
response['Cache-Control'] = 'no-cache, no-store'
|
|
62
|
-
response['X-Accel-Buffering'] = 'no'
|
|
63
|
-
|
|
64
|
-
return response
|
|
File without changes
|
|
File without changes
|
|
File without changes
|