django-spire 0.24.2__py3-none-any.whl → 0.25.0__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 (33) hide show
  1. django_spire/consts.py +1 -1
  2. django_spire/contrib/admin/__init__.py +0 -0
  3. django_spire/contrib/admin/admin.py +140 -0
  4. django_spire/contrib/choices/__init__.py +0 -0
  5. django_spire/contrib/choices/choices.py +9 -0
  6. django_spire/contrib/choices/tests/__init__.py +0 -0
  7. django_spire/contrib/choices/tests/test_choices.py +62 -0
  8. django_spire/core/static/django_spire/css/app-printing.css +25 -0
  9. django_spire/core/templates/django_spire/dropdown/ellipsis_modal_dropdown.html +15 -3
  10. django_spire/core/templates/django_spire/element/attribute_element.html +7 -0
  11. django_spire/core/templates/django_spire/element/copy_to_clipboard_element.html +31 -0
  12. django_spire/metric/report/__init__.py +7 -0
  13. django_spire/metric/report/helper.py +92 -0
  14. django_spire/metric/report/report.py +79 -13
  15. django_spire/metric/report/templates/django_spire/metric/report/form/report_form.html +32 -10
  16. django_spire/metric/report/templates/django_spire/metric/report/print/report_print.html +29 -16
  17. django_spire/metric/report/tools.py +2 -0
  18. django_spire/metric/report/views/page_views.py +27 -5
  19. django_spire/notification/app/templates/django_spire/notification/app/dropdown/notification_dropdown.html +10 -10
  20. django_spire/notification/app/templates/django_spire/notification/app/dropdown/notification_dropdown_content.html +1 -33
  21. django_spire/notification/app/templates/django_spire/notification/app/item/notification_item.html +24 -23
  22. django_spire/notification/app/templates/django_spire/notification/app/page/list_page.html +1 -1
  23. django_spire/notification/app/templates/django_spire/notification/app/scroll/container/dropdown_container.html +54 -0
  24. django_spire/notification/app/templates/django_spire/notification/app/scroll/item/items.html +5 -0
  25. django_spire/notification/app/urls/template_urls.py +9 -2
  26. django_spire/notification/app/views/page_views.py +2 -10
  27. django_spire/notification/app/views/template_views.py +22 -7
  28. {django_spire-0.24.2.dist-info → django_spire-0.25.0.dist-info}/METADATA +2 -2
  29. {django_spire-0.24.2.dist-info → django_spire-0.25.0.dist-info}/RECORD +32 -23
  30. django_spire/notification/app/templates/django_spire/notification/app/card/list_card.html +0 -11
  31. {django_spire-0.24.2.dist-info → django_spire-0.25.0.dist-info}/WHEEL +0 -0
  32. {django_spire-0.24.2.dist-info → django_spire-0.25.0.dist-info}/licenses/LICENSE.md +0 -0
  33. {django_spire-0.24.2.dist-info → django_spire-0.25.0.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,7 @@
4
4
  <div class="col-11 col-md-10 col-lg-8 col-xl-6 mx-auto my-3">
5
5
 
6
6
  <div class="row">
7
- <div class="col fs-5 text-center">
7
+ <div class="col h5 text-center text-app-primary">
8
8
  {{ report.title }}
9
9
  </div>
10
10
  </div>
@@ -23,12 +23,19 @@
23
23
 
24
24
  {% for argument, params in report_run_arguments.items %}
25
25
  <div class="row">
26
- <div class="col mb-2">
27
-
26
+ <div class="col">
28
27
  <label class="form-label">
29
- {{ argument|underscores_to_spaces|title }}
28
+ {{ argument|underscores_to_spaces|title }} <span class="text-danger">*</span>
30
29
  </label>
31
- {% if params.annotation == 'str' %}
30
+ </div>
31
+ </div>
32
+ <div class="row">
33
+ <div class="col mb-2 ps-4">
34
+ {% if params.annotation == 'date' %}
35
+ <input class="form-control" type="date" name="{{ argument }}" value="{{ params.default|date:'Y-m-d' }}">
36
+ {% elif params.annotation == 'datetime' %}
37
+ <input class="form-control" type="datetime-local" name="{{ argument }}" value="{{ params.default|date:'Y-m-d\\TH:i:s' }}">
38
+ {% elif params.annotation == 'str' %}
32
39
  <input class="form-control" type="text" name="{{ argument }}" value="{{ params.default }}">
33
40
  {% elif params.annotation == 'int' %}
34
41
  <input class="form-control" type="number" name="{{ argument }}"
@@ -37,22 +44,37 @@
37
44
  <input class="form-control" type="number" name="{{ argument }}"
38
45
  value="{{ params.default }}">
39
46
  {% elif params.annotation == 'bool' %}
40
- <br><input class="form-check-input" type="checkbox" name="{{ argument }}"
41
- value="{{ params.default }}">
47
+ <div class="form-check form-switch">
48
+ <input class="form-check-input" type="checkbox" role="switch" {% if params.default %}checked{% endif %} id="flexSwitchCheckDefault">
49
+ </div>
50
+ {% elif params.annotation == 'multi_select' %}
51
+ <select class="form-select" multiple size="8" name="{{ argument }}" aria-selected="{{ params.default }}">
52
+ {% for key, val in params.choices %}
53
+ <option value="{{ key }}">{{ val }}</option>
54
+ {% endfor %}
55
+ </select>
42
56
  {% elif params.annotation == 'select' %}
43
57
  <select class="form-select" name="{{ argument }}" aria-selected="{{ params.default }}">
44
58
  {% for key, val in params.choices %}
45
59
  <option value="{{ key }}">{{ val }}</option>
46
60
  {% endfor %}
47
61
  </select>
62
+ {% else %}
63
+ <br>
64
+ <span class="text-danger">Unsupported parameter type: {{ params.annotation }}</span>
48
65
  {% endif %}
49
66
  </div>
50
67
  </div>
51
68
  {% endfor %}
52
69
 
53
- <div class="row">
54
- <div class="col mt-3 text-center">
55
- <input class="btn btn-primary" type="submit" value="Run Report">
70
+ <div x-data="{
71
+ loading: false
72
+ }" class="row">
73
+ <div class="col mt-3 text-center" x-show="!loading">
74
+ <input class="btn btn-app-primary" @click="loading = true" type="submit" value="Run Report">
75
+ </div>
76
+ <div class="col mt-3 text-center text-app-primary" x-show="loading">
77
+ <span class="spinner-border" role="status" aria-hidden="true"></span>
56
78
  </div>
57
79
  </div>
58
80
  <div class="row">
@@ -2,41 +2,41 @@
2
2
 
3
3
  <div class="row mb-1 font-monospace">
4
4
  <div class="col">
5
- <div class="fw-bold">
5
+ <div class="h5 fw-bold">
6
6
  {{ report.title }}
7
7
  </div>
8
8
  </div>
9
9
  </div>
10
10
 
11
- <div class="row mx-0 mb-3 text-muted fw-normal fs--2 border font-monospace">
11
+ <div class="row mx-0 mb-3 text-muted fw-normal fs-print-2 border font-monospace">
12
12
  {% if report.description %}
13
13
  <div class="col-auto ps-1 pe-3">
14
- Description: {{ report.description }}
14
+ Description: <span class="fw-bold">{{ report.description }}</span>
15
15
  </div>
16
16
  {% endif %}
17
- <div class="col-auto ps-1 pe-3">
18
- Printed On: {% now "D, M j, Y" %} at {% now "g:i A" %}
17
+ <div class="col-auto ps-1 pe-3">
18
+ Printed On: <span class="fw-bold">{% now "D, M j, Y" %} at {% now "g:i A" %}</span>
19
19
  </div>
20
- <div class="col-auto ps-1 pe-3">
21
- Financially Accurate: {% if report.is_financially_accurate %}True{% else %}False{% endif %}
20
+ <div class="col-auto ps-1 pe-3">
21
+ Financially Accurate: <span class="fw-bold">{% if report.is_financially_accurate %}True{% else %}False{% endif %}</span>
22
22
  </div>
23
23
  {% for argument, value in report_run_arguments_values.items %}
24
24
  <div class="col-auto ps-1 pe-3">
25
- {{ argument|underscores_to_spaces|title }}: {{ value }}
25
+ {{ argument|underscores_to_spaces|title }}: <span class="fw-bold">{{ value }}</span>
26
26
  </div>
27
27
  {% endfor %}
28
28
  </div>
29
29
 
30
30
  <div class="row">
31
- <div class="col fs--2">
31
+ <div class="col fs-print-2">
32
32
 
33
- <table class="table table-sm table-hover table-print">
33
+ <table class="table table-sm table-hover table-print align-middle">
34
34
  <thead>
35
35
  {% for column in report.columns %}
36
- <th class="align-text-top {{ column.css_class }}">
36
+ <th class="align-text-top {{ column.css_class }}" style="border-bottom-width: 4px;">
37
37
  {{ column.title }}
38
38
  {% if column.sub_title %}
39
- <span class="text-muted fw-normal fs--2">
39
+ <span class="text-muted fw-normal fs-print-3">
40
40
  <br>{{ column.sub_title }}
41
41
  </span>
42
42
  {% endif %}
@@ -45,12 +45,24 @@
45
45
  </thead>
46
46
  <tbody>
47
47
  {% for row in report.rows %}
48
+ {% if row.page_break %}
49
+ <tr style="page-break-before: always;"></tr>
50
+ {% endif %}
48
51
  <tr class="{% if row.bold %}fw-bold{% endif %}"
49
- {% if row.page_break %}style="page-break-before: always;"{% endif %}>
52
+ style="{% if row.border_top %}border-top-width: 4px;{% endif %}{% if row.border_bottom %}border-bottom-width: 4px;{% endif %}">
50
53
  {% if row.span_all_columns %}
51
54
  <td colspan="{{ report.column_count }}">
52
55
  {% for cell in row.cells %}
53
- {{ cell.value|safe }}
56
+ {% if cell.value %}
57
+ {{ cell.value }}
58
+ {% else %}
59
+ &nbsp;
60
+ {% endif %}
61
+ {% if cell.sub_value %}
62
+ <span class="text-muted fw-normal fs-print-3">
63
+ <br>{{ cell.sub_value_verbose }}
64
+ </span>
65
+ {% endif %}
54
66
  {% endfor %}
55
67
  </td>
56
68
  {% else %}
@@ -58,8 +70,9 @@
58
70
  <td class="{{ cell.css_class }}">
59
71
  {{ cell.value_verbose }}
60
72
  {% if cell.sub_value %}
61
- <br>
62
- {{ cell.sub_value_verbose }}
73
+ <span class="text-muted fw-normal fs-print-3">
74
+ <br>{{ cell.sub_value_verbose }}
75
+ </span>
63
76
  {% endif %}
64
77
  </td>
65
78
  {% endfor %}
@@ -1,3 +1,5 @@
1
+ import datetime
2
+
1
3
  from django_spire.metric.report.enums import ColumnType
2
4
 
3
5
 
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from datetime import datetime
3
4
  from typing import TYPE_CHECKING
4
5
 
5
6
  from django.conf import settings
@@ -37,9 +38,9 @@ def report_view(request: WSGIRequest) -> TemplateResponse:
37
38
  report_registry_class()
38
39
  )
39
40
 
40
- context_data = {
41
- 'registry': page_report_registry,
42
- }
41
+ context_data = dict()
42
+
43
+ context_data['registry'] = page_report_registry
43
44
 
44
45
  if request.GET:
45
46
  report_key_stack = request.GET.get('report_key_stack', None)
@@ -57,9 +58,30 @@ def report_view(request: WSGIRequest) -> TemplateResponse:
57
58
 
58
59
  context_data['report_run_arguments_values'] = {}
59
60
 
60
- for argument in report.run_arguments:
61
+ for argument in context_data['report_run_arguments']:
61
62
  if context_data['report_run_arguments'][argument]['annotation'] == 'bool':
62
63
  get_request_value = request.GET.get(argument, False)
64
+
65
+ elif context_data['report_run_arguments'][argument]['annotation'] == 'date':
66
+ date_str = request.GET.get(argument, None)
67
+
68
+ if date_str:
69
+ get_request_value = datetime.strptime(date_str, '%Y-%m-%d').date()
70
+ else:
71
+ get_request_value = date_str
72
+
73
+
74
+ elif context_data['report_run_arguments'][argument]['annotation'] == 'datetime':
75
+ datetime_str = request.GET.get(argument, None)
76
+
77
+ if datetime_str:
78
+ get_request_value = datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S')
79
+ else:
80
+ get_request_value = datetime_str
81
+
82
+ elif context_data['report_run_arguments'][argument]['annotation'] == 'multi_select':
83
+ get_request_value = request.GET.getlist(argument, [])
84
+
63
85
  else:
64
86
  get_request_value = request.GET.get(argument, None)
65
87
 
@@ -73,7 +95,7 @@ def report_view(request: WSGIRequest) -> TemplateResponse:
73
95
  ReportRun.objects.create(
74
96
  report_key_stack=report_key_stack,
75
97
  )
76
- report.run()
98
+ report.run(**context_data['report_run_arguments_values'])
77
99
 
78
100
  context_data['report'] = report
79
101
  context_data['report_run_count'] = ReportRun.objects.run_count(report_key_stack)
@@ -4,28 +4,28 @@
4
4
  <div x-data="{
5
5
  new_notification: false,
6
6
  async init(){
7
- await this.check_new_notifications()
7
+ await this.check_new_notifications();
8
8
  setInterval(await this.check_new_notifications, 30000);
9
9
  },
10
10
 
11
11
  async check_new_notifications(){
12
- let url = '{% url "django_spire:notification:app:json:check_new" %}'
13
- let response = await django_glue_fetch(url)
14
- this.new_notification = response.has_new_notifications
12
+ let url = '{% url "django_spire:notification:app:json:check_new" %}';
13
+ let response = await django_glue_fetch(url);
14
+ this.new_notification = response.has_new_notifications;
15
15
  },
16
16
 
17
17
  async render_dropdown(){
18
18
  let dropdown_content = new ViewGlue(
19
19
  url='{% url "django_spire:notification:app:template:notification_dropdown" %}',
20
20
  shared_payload={app_notification_list_url: '{{ app_notification_list_url|default:"" }}'}
21
- )
22
- await dropdown_content.render_inner($refs.spire_notification_dropdown_content)
23
- await this.mark_notifications_as_viewed()
21
+ );
22
+ await dropdown_content.render_inner($refs.spire_notification_dropdown_content);
23
+ await this.mark_notifications_as_viewed();
24
24
  },
25
25
 
26
26
  async mark_notifications_as_viewed(){
27
- let response = await django_glue_fetch('{% url "django_spire:notification:app:json:set_viewed" %}')
28
- this.new_notification = false
27
+ let response = await django_glue_fetch('{% url "django_spire:notification:app:json:set_viewed" %}');
28
+ this.new_notification = false;
29
29
  }
30
30
 
31
31
  }"
@@ -44,5 +44,5 @@
44
44
  {% block dropdown_position %}top-100 end-50{% endblock %}
45
45
 
46
46
  {% block dropdown_content %}
47
- <div x-ref="spire_notification_dropdown_content"></div>
47
+ <div :style="{ width: window.innerWidth < 768 ? (window.innerWidth / 2).toFixed(0) + 'px' : '350px' }" x-ref="spire_notification_dropdown_content"></div>
48
48
  {% endblock %}
@@ -1,33 +1 @@
1
- <div
2
- :style="window.innerWidth < 768
3
- ? 'width: 350px; position: fixed; top: 5%; left: 50%; transform: translateX(-50%);'
4
- : 'width: 350px'"
5
- class="container border rounded-2 bg-app-layer-two"
6
- >
7
- <div class="col-12 w-100">
8
- <h6 class="mt-2 ms-2 text-center">Notifications</h6>
9
- <hr class="m-0">
10
- </div>
11
-
12
- <div
13
- style="max-height: 300px !important;"
14
- class="text-start overflow-y-scroll overflow-x-hidden"
15
- >
16
- {% for app_notification in app_notification_list %}
17
- <div class="col-12">
18
- {% include app_notification.template %}
19
- </div>
20
- {% empty %}
21
- No Notifications
22
- {% endfor %}
23
- </div>
24
- <div class="col-12">
25
- <hr class="m-0">
26
- </div>
27
- <div class="col-12 fs-7 text-center py-1">
28
- {% if not app_notification_list_url %}
29
- {% url "django_spire:notification:app:page:list" as app_notification_list_url %}
30
- {% endif %}
31
- <a href='{{ app_notification_list_url }}' class="text-decoration-none text-app-secondary my-2">View All</a>
32
- </div>
33
- </div>
1
+ {% include 'django_spire/notification/app/scroll/container/dropdown_container.html' with endpoint=notification_endpoint container_height='300px' batch_size=10 %}
@@ -1,25 +1,26 @@
1
- <div class="row pt-1 px-3">
2
- <div class="col-12">
3
- <div class="row bg-app-layer-two-hover rounded">
4
- {% if app_notification.notification.url %}
5
- <a href="{{ app_notification.notification.url }}" class="col-12">
6
- {% endif %}
7
- <div class="col-12">
8
- <div>
9
- <span class="fs-7 fw-semibold">{{ app_notification.notification.title }}</span>
10
- {% if not app_notification.viewed %}
11
- {% include 'django_spire/badge/primary_badge.html' with badge_text='New' %}
12
- {% endif %}
13
- </div>
14
- <span class="fs--1">{{ app_notification.notification.body }}</span><br>
15
- <span class="text-app-secondary text-muted fs--2">{{ app_notification.verbose_time_since_delivered }}</span>
16
- </div>
17
- {% if app_notification.notification.url %}
18
- </a>
19
- {% endif %}
20
- </div>
1
+ {% extends 'django_spire/item/infinite_scroll_item.html' %}
2
+
3
+ {% block item_content %}
4
+ {% if app_notification.notification.url %}
5
+ <a href="{{ app_notification.notification.url }}"
6
+ {% else %}
7
+ <div
8
+ {% endif %}
9
+ class="row bg-app-layer-two-hover rounded m-0"
10
+ >
11
+ <div class="col-12">
12
+ <span class="fs-7 fw-semibold">{{ app_notification.notification.title }}</span>
13
+ {% if not app_notification.viewed %}
14
+ {% include 'django_spire/badge/primary_badge.html' with badge_text='New' %}
15
+ {% endif %}
16
+ </div>
17
+ <div class="col-12">
18
+ <span class="fs--1">{{ app_notification.notification.body }}</span><br>
19
+ <span class="text-app-secondary text-muted fs--2">{{ app_notification.verbose_time_since_delivered }}</span>
20
+ </div>
21
+ {% if app_notification.notification.url %}
22
+ </a>
23
+ {% else %}
21
24
  </div>
22
- {% if not forloop.last %}
23
- <hr class="m-0 mt-1">
24
25
  {% endif %}
25
- </div>
26
+ {% endblock %}
@@ -1,5 +1,5 @@
1
1
  {% extends 'django_spire/page/full_page.html' %}
2
2
 
3
3
  {% block full_page_content %}
4
- {% include "django_spire/notification/app/card/list_card.html" %}
4
+ {% include "django_spire/card/infinite_scroll_card.html" with card_title='Notifications' endpoint=notification_endpoint scroll_height='55vh' %}
5
5
  {% endblock %}
@@ -0,0 +1,54 @@
1
+ {% extends 'django_spire/infinite_scroll/base.html' %}
2
+
3
+ {% block scroll_wrapper_class %}bg-app-layer-two rounded-2{% endblock %}
4
+
5
+ {% block scroll_container %}
6
+ <div class="row">
7
+ <div class="col-12">
8
+ <div
9
+ :style="{
10
+ maxHeight: '{{ container_height|default:'300px' }}',
11
+ overflowX: 'hidden',
12
+ overflowY: 'auto',
13
+ overscrollBehavior: 'contain',
14
+ WebkitOverflowScrolling: 'touch',
15
+ maxWidth: window.innerWidth < 768 ? (window.innerWidth / 2).toFixed(0) + 'px' : '350px',
16
+ }"
17
+ x-ref="scroll_container"
18
+ :data-scroll-id="scroll_id"
19
+ >
20
+ <div x-ref="content_container">
21
+ {% block scroll_content %}{% endblock %}
22
+ </div>
23
+
24
+ <div style="height: 10px;" x-ref="infinite_scroll_trigger"></div>
25
+ </div>
26
+
27
+ <template x-if="show_loading && !is_refreshing">
28
+ <div
29
+ class="position-absolute d-flex justify-content-center align-items-center"
30
+ style="top: 0; left: 0; right: 0; bottom: 0; background: color-mix(in srgb, var(--app-layer-one) 85%, transparent);"
31
+ >
32
+ <div class="spinner-border text-app-primary" role="status"></div>
33
+ </div>
34
+ </template>
35
+ </div>
36
+ </div>
37
+ {% endblock %}
38
+
39
+ {% block scroll_footer %}
40
+ <div class="row text-center border-top border-dark-subtle m-0">
41
+ <div class="col-12">
42
+ <span class="fs-7 text-app-secondary">
43
+ Showing <span x-text="loaded_count"></span> of <span x-text="total_count"></span> {{ footer_label|default:'items' }}
44
+ </span>
45
+ </div>
46
+
47
+ <div class="col-12 fs-7 text-center py-1">
48
+ {% if not app_notification_list_url %}
49
+ {% url "django_spire:notification:app:page:list" as app_notification_list_url %}
50
+ {% endif %}
51
+ <a href='{{ app_notification_list_url }}' class="text-decoration-none text-app-secondary my-2">View All</a>
52
+ </div>
53
+ </div>
54
+ {% endblock %}
@@ -0,0 +1,5 @@
1
+ {% for app_notification in notifications %}
2
+ <div class="col-12 p-0">
3
+ {% include app_notification.template %}
4
+ </div>
5
+ {% endfor %}
@@ -8,7 +8,14 @@ from django_spire.notification.app.views import template_views
8
8
  app_name = 'django_spire_notification'
9
9
 
10
10
  urlpatterns = [
11
- path('notficiation/dropdown/template/',
11
+ path(
12
+ 'notficiation/scroll/items',
13
+ template_views.notification_infinite_scroll_view,
14
+ name='scroll_items'
15
+ ),
16
+ path(
17
+ 'notficiation/dropdown/template/',
12
18
  template_views.notification_dropdown_template_view,
13
- name='notification_dropdown')
19
+ name='notification_dropdown'
20
+ )
14
21
  ]
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from django.contrib.auth.decorators import login_required
6
+ from django.urls import reverse
6
7
 
7
8
  from django_spire.contrib.generic_views import portal_views
8
9
 
@@ -15,18 +16,9 @@ if TYPE_CHECKING:
15
16
 
16
17
  @login_required()
17
18
  def app_notification_list_view(request: WSGIRequest) -> TemplateResponse:
18
- app_notification_list = (
19
- AppNotification.objects.active()
20
- .is_sent()
21
- .annotate_is_viewed_by_user(request.user)
22
- .select_related('notification')
23
- .distinct()
24
- .ordered_by_priority_and_sent_datetime()
25
- )
26
-
27
19
  return portal_views.list_view(
28
20
  request,
29
- context_data={'notification_list': app_notification_list},
21
+ context_data={'notification_endpoint': reverse('django_spire:notification:app:template:scroll_items')},
30
22
  model=AppNotification,
31
23
  template='django_spire/notification/app/page/list_page.html'
32
24
  )
@@ -1,24 +1,25 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
-
5
4
  from typing import TYPE_CHECKING
6
5
 
7
6
  from django.contrib.auth.models import AnonymousUser
8
- from django.template.response import TemplateResponse
7
+ from django.urls import reverse
9
8
 
9
+ from django_spire.contrib.generic_views.portal_views import infinite_scrolling_view
10
+ from django.template.response import TemplateResponse
10
11
  from django_spire.notification.app.models import AppNotification
11
12
 
13
+
12
14
  if TYPE_CHECKING:
13
15
  from django.core.handlers.wsgi import WSGIRequest
14
16
 
15
-
16
- def notification_dropdown_template_view(request: WSGIRequest) -> TemplateResponse:
17
+ def notification_infinite_scroll_view(request: WSGIRequest) -> TemplateResponse:
17
18
  if isinstance(request.user, AnonymousUser):
18
- app_notification_list = []
19
+ notifications = []
19
20
 
20
21
  else:
21
- app_notification_list = (
22
+ notifications = (
22
23
  AppNotification.objects.active()
23
24
  .is_sent()
24
25
  .annotate_is_viewed_by_user(request.user)
@@ -29,11 +30,25 @@ def notification_dropdown_template_view(request: WSGIRequest) -> TemplateRespons
29
30
 
30
31
  body_data = json.loads(request.body.decode('utf-8'))
31
32
 
33
+ return infinite_scrolling_view(
34
+ request,
35
+ queryset=notifications,
36
+ queryset_name='notifications',
37
+ context_data={
38
+ 'app_notification_list_url': body_data.get('app_notification_list_url'),
39
+ },
40
+ template='django_spire/notification/app/scroll/item/items.html',
41
+ )
42
+
43
+
44
+ def notification_dropdown_template_view(request: WSGIRequest) -> TemplateResponse:
45
+ body_data = json.loads(request.body.decode('utf-8'))
46
+
32
47
  return TemplateResponse(
33
48
  request,
34
49
  context={
35
- 'app_notification_list': app_notification_list,
36
50
  'app_notification_list_url': body_data.get('app_notification_list_url'),
51
+ 'notification_endpoint': reverse('django_spire:notification:app:template:scroll_items')
37
52
  },
38
53
  template='django_spire/notification/app/dropdown/notification_dropdown_content.html'
39
54
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-spire
3
- Version: 0.24.2
3
+ Version: 0.25.0
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) 2025 Stratus Advanced Technologies and Contributors.
@@ -52,7 +52,7 @@ Requires-Dist: crispy-bootstrap5==2024.10
52
52
  Requires-Dist: dandy>=1.3.5
53
53
  Requires-Dist: django>=5.1.8
54
54
  Requires-Dist: django-crispy-forms==2.3
55
- Requires-Dist: django-glue>=0.8.1
55
+ Requires-Dist: django-glue>=0.8.12
56
56
  Requires-Dist: django-sendgrid-v5
57
57
  Requires-Dist: django-storages==1.14.5
58
58
  Requires-Dist: docutils