django-spire 0.25.1__py3-none-any.whl → 0.26.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.
- django_spire/ai/chat/router.py +10 -20
- django_spire/ai/chat/templates/django_spire/ai/chat/dropdown/ellipsis_dropdown.html +5 -3
- django_spire/ai/chat/templates/django_spire/ai/chat/message/default_message.html +6 -2
- django_spire/ai/chat/templatetags/spire_ai_chat_tags.py +19 -0
- django_spire/ai/chat/tests/test_router/test_spire_chat_router.py +20 -88
- django_spire/auth/templates/django_spire/auth/element/android_and_chrome_app_install_element.html +33 -0
- django_spire/auth/templates/django_spire/auth/element/ios_app_install_element.html +48 -0
- django_spire/auth/templates/django_spire/auth/page/auth_page.html +2 -1
- django_spire/auth/templates/django_spire/auth/page/login_page.html +2 -0
- django_spire/comment/mixins.py +3 -3
- django_spire/comment/templates/django_spire/comment/card/comment_list_card.html +8 -5
- django_spire/comment/templates/django_spire/comment/form/comment_form.html +3 -3
- django_spire/comment/templates/django_spire/comment/form/content/comment_form_content.html +1 -0
- django_spire/comment/templates/django_spire/comment/item/comment_item_ellipsis.html +12 -8
- django_spire/comment/views.py +8 -8
- django_spire/consts.py +1 -1
- django_spire/contrib/form/utils.py +3 -3
- django_spire/contrib/progress/session.py +1 -1
- django_spire/contrib/queryset/filter_tools.py +56 -14
- django_spire/contrib/queryset/mixins.py +24 -3
- django_spire/contrib/service/django_model_service.py +5 -6
- django_spire/core/management/commands/spire_startapp.py +42 -25
- django_spire/core/management/commands/spire_startapp_pkg/exceptions.py +5 -0
- django_spire/core/management/commands/spire_startapp_pkg/maps.py +64 -32
- django_spire/core/management/commands/spire_startapp_pkg/template/app/constants.py.template +1 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/app/forms.py.template +4 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/app/models.py.template +2 -1
- django_spire/core/management/commands/spire_startapp_pkg/template/app/querysets.py.template +15 -6
- django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/__init__.py.template +1 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/form_urls.py.template +6 -6
- django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/page_urls.py.template +2 -2
- django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/template_urls.py.template +12 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/app/views/form_views.py.template +10 -11
- django_spire/core/management/commands/spire_startapp_pkg/template/app/views/page_views.py.template +17 -3
- django_spire/core/management/commands/spire_startapp_pkg/template/app/views/template_views.py.template +40 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${form_card_template_name}.html.template +1 -1
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_base_card_template_name}.html.template +16 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_items_card_template_name}.html.template +16 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_table_card_template_name}.html.template +16 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/container/${list_container_template_name}.html.template +1 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/form/${list_filter_form_template_name}.html.template +30 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/item/${item_template_name}.html.template +32 -20
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/item/${list_items_template_name}.html.template +3 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/page/${detail_page_template_name}.html.template +3 -3
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/page/${form_page_template_name}.html.template +2 -2
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/page/${list_page_template_name}.html.template +2 -2
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/table/${table_row_template_name}.html.template +6 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/table/${table_rows_template_name}.html.template +3 -0
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/table/${table_template_name}.html.template +6 -0
- django_spire/core/management/commands/spire_startapp_pkg/user_input.py +82 -9
- django_spire/core/management/commands/spire_startapp_pkg/validator.py +19 -6
- django_spire/core/middleware.py +2 -3
- django_spire/core/querysets.py +19 -0
- django_spire/core/static/django_spire/js/theme.js +10 -7
- django_spire/core/templates/django_spire/badge/base_badge.html +2 -3
- django_spire/core/templates/django_spire/base/base.html +1 -0
- django_spire/core/templates/django_spire/button/base_button.html +2 -1
- django_spire/core/templates/django_spire/card/title_card.html +13 -10
- django_spire/core/templates/django_spire/container/container.html +1 -1
- django_spire/core/templates/django_spire/filtering/form/base_session_filter_form.html +1 -1
- django_spire/core/templates/django_spire/form/field/_base_file_field.html +216 -0
- django_spire/core/templates/django_spire/form/field/_multi_checkbox_field.html +52 -0
- django_spire/core/templates/django_spire/form/field/base_field.html +128 -0
- django_spire/core/templates/django_spire/form/field/char_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/color_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/date_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/datetime_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/decimal_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/element/select_checkmark_element.html +4 -0
- django_spire/core/templates/django_spire/form/field/element/select_down_arrow_element.html +5 -0
- django_spire/core/templates/django_spire/form/field/email_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/input_field.html +13 -0
- django_spire/core/templates/django_spire/form/field/item/select_choice_item.html +15 -0
- django_spire/core/templates/django_spire/form/field/item/selected_choice_item.html +5 -0
- django_spire/core/templates/django_spire/form/field/list_field.html +112 -0
- django_spire/core/templates/django_spire/form/field/multi_file_field.html +90 -0
- django_spire/core/templates/django_spire/form/field/multi_select_field.html +155 -0
- django_spire/core/templates/django_spire/form/field/number_field.html +11 -0
- django_spire/core/templates/django_spire/form/field/password_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/radio_field.html +24 -0
- django_spire/core/templates/django_spire/form/field/range_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/search_and_select_field.html +119 -0
- django_spire/core/templates/django_spire/form/field/search_field.html +5 -0
- django_spire/core/templates/django_spire/form/field/select_field.html +78 -0
- django_spire/core/templates/django_spire/form/field/single_checkbox_field.html +27 -0
- django_spire/core/templates/django_spire/form/field/single_file_field.html +90 -0
- django_spire/core/templates/django_spire/form/field/telephone_field.html +1 -0
- django_spire/core/templates/django_spire/form/field/text_field.html +11 -0
- django_spire/core/templates/django_spire/form/field/time_field.html +1 -0
- django_spire/core/templates/django_spire/infinite_scroll/base.html +2 -1
- django_spire/core/templatetags/model_tags.py +34 -0
- django_spire/knowledge/entry/forms.py +1 -1
- django_spire/knowledge/entry/models.py +18 -0
- django_spire/knowledge/entry/querysets.py +8 -6
- django_spire/knowledge/entry/services/processor_service.py +1 -0
- django_spire/knowledge/entry/services/search_index_service.py +61 -0
- django_spire/knowledge/entry/services/search_service.py +99 -0
- django_spire/knowledge/entry/services/service.py +6 -0
- django_spire/knowledge/entry/version/services/processor_service.py +2 -0
- django_spire/knowledge/entry/version/tests/factories.py +9 -4
- django_spire/knowledge/entry/version/tests/test_services.py +7 -16
- django_spire/knowledge/intelligence/bots/knowledge_answer_bot.py +40 -6
- django_spire/knowledge/intelligence/bots/knowledge_entries_bot.py +4 -2
- django_spire/knowledge/intelligence/bots/search_preprocessing_bot.py +32 -0
- django_spire/knowledge/intelligence/intel/entry_intel.py +12 -0
- django_spire/knowledge/intelligence/router.py +47 -4
- django_spire/knowledge/intelligence/workflows/knowledge_workflow.py +24 -42
- django_spire/knowledge/intelligence/workflows/search_preprocessing_workflow.py +78 -0
- django_spire/knowledge/management/__init__.py +0 -0
- django_spire/knowledge/management/commands/__init__.py +0 -0
- django_spire/knowledge/management/commands/rebuild_knowledge_search_index.py +16 -0
- django_spire/knowledge/migrations/0010_entry__search_text_entry__search_vector_and_more.py +40 -0
- django_spire/knowledge/templates/django_spire/knowledge/message/knowledge_message_intel.html +31 -23
- django_spire/metric/report/enums.py +11 -5
- django_spire/metric/report/report.py +24 -12
- django_spire/metric/report/tools.py +14 -4
- django_spire/testing/playwright/fixtures.py +4 -5
- {django_spire-0.25.1.dist-info → django_spire-0.26.0.dist-info}/METADATA +1 -1
- {django_spire-0.25.1.dist-info → django_spire-0.26.0.dist-info}/RECORD +123 -69
- django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_card_template_name}.html.template +0 -18
- /django_spire/{core/management/commands/spire_startapp_pkg/template/app/tests/test_intelligence/__init__.py.template → ai/chat/templatetags/__init__.py} +0 -0
- {django_spire-0.25.1.dist-info → django_spire-0.26.0.dist-info}/WHEEL +0 -0
- {django_spire-0.25.1.dist-info → django_spire-0.26.0.dist-info}/licenses/LICENSE.md +0 -0
- {django_spire-0.25.1.dist-info → django_spire-0.26.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{% extends 'django_spire/filtering/form/base_session_filter_form.html' %}
|
|
2
|
+
|
|
3
|
+
{% load session_tags %}
|
|
4
|
+
|
|
5
|
+
{% block session_filter_key %}{{ filter_session.session_key }}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block filter_content %}
|
|
8
|
+
<div
|
|
9
|
+
class="row g-2 mb-2"
|
|
10
|
+
x-data="{
|
|
11
|
+
async init() {
|
|
12
|
+
this.search_field.set_attribute('placeholder', 'Search...')
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
session_controller: new SessionController('{% session_controller_to_json filter_session.session_key %}'),
|
|
16
|
+
search_field: new GlueCharField(
|
|
17
|
+
'search',
|
|
18
|
+
{
|
|
19
|
+
value: '{{ filter_session.search|default:"" }}',
|
|
20
|
+
label: 'Search',
|
|
21
|
+
name: 'search',
|
|
22
|
+
}
|
|
23
|
+
),
|
|
24
|
+
}"
|
|
25
|
+
>
|
|
26
|
+
<div class="col-3">
|
|
27
|
+
{% include 'django_glue/form/field/char_field.html' with glue_field='search_field' %}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
{% endblock %}
|
|
@@ -1,24 +1,36 @@
|
|
|
1
|
-
{% extends 'django_spire/item/
|
|
1
|
+
{% extends 'django_spire/item/infinite_scroll_item.html' %}
|
|
2
2
|
|
|
3
|
-
{% block
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
{% endblock %}
|
|
3
|
+
{% block item_content %}
|
|
4
|
+
<div class="row justify-content-center align-items-center position-relative">
|
|
5
|
+
<div class="col">
|
|
6
|
+
<div class="row justify-content-between align-items-center {% block item_row_content_outer_class %}{% endblock %}">
|
|
7
|
+
<div class="col">
|
|
8
|
+
<div class="row align-items-center {% block item_content_gutter %}g-2{% endblock %}">
|
|
9
|
+
<div class="row mt-3">
|
|
10
|
+
<div class="col-6">
|
|
11
|
+
{% url '${url_reverse_path}:page:detail' pk=${context_single_var}.pk as ${context_single_var}_view_url %}
|
|
12
|
+
{% include 'django_spire/element/attribute_element.html' with attribute_title='${model_verbose_name}' attribute_value=${context_single_var}.name attribute_href=${context_single_var}_view_url %}
|
|
13
|
+
</div>
|
|
14
|
+
<div class="col-6">
|
|
15
|
+
{% include 'django_spire/element/attribute_element.html' with attribute_title='Description' attribute_value=${context_single_var}.description %}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="col-auto top-0 end-0 position-absolute position-lg-static pt-2 pt-lg-0">
|
|
21
|
+
{% url '${url_reverse_path}:page:detail' pk=${context_single_var}.pk as ${context_single_var}_view_url %}
|
|
7
22
|
|
|
8
|
-
{%
|
|
9
|
-
|
|
10
|
-
{%
|
|
23
|
+
{% if perms.${permission_prefix}.change_${model_instance_name} %}
|
|
24
|
+
{% url '${url_reverse_path}:form:update' pk=${context_single_var}.pk as ${context_single_var}_edit_url %}
|
|
25
|
+
{% endif %}
|
|
11
26
|
|
|
12
|
-
{%
|
|
13
|
-
|
|
27
|
+
{% if perms.${permission_prefix}.delete_${model_instance_name} %}
|
|
28
|
+
{% url '${url_reverse_path}:form:delete' pk=${context_single_var}.pk as ${context_single_var}_delete_url %}
|
|
29
|
+
{% endif %}
|
|
14
30
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{% endif %}
|
|
22
|
-
|
|
23
|
-
{% include 'django_spire/dropdown/ellipsis_dropdown.html' with view_url=${context_single_var}_view_url edit_url=${context_single_var}_edit_url delete_url=${context_single_var}_delete_url %}
|
|
24
|
-
{% endblock %}
|
|
31
|
+
{% include 'django_spire/dropdown/ellipsis_dropdown.html' with view_url=${context_single_var}_view_url edit_url=${context_single_var}_edit_url delete_url=${context_single_var}_delete_url %}
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
{% endblock %}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{% extends 'django_spire/page/full_page.html' %}
|
|
2
2
|
|
|
3
|
-
{% block
|
|
3
|
+
{% block full_page_content %}
|
|
4
4
|
<div class="row g-3">
|
|
5
5
|
<div class="col-12">
|
|
6
|
-
{% include '${template_directory_path}/card/${detail_card_template_name}' %}
|
|
6
|
+
{% include '${template_directory_path}/card/${detail_card_template_name}.html' %}
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
9
|
<div class="col-4">
|
|
10
|
-
{% include '
|
|
10
|
+
{% include 'django_spire/activity/card/list_card.html' with activity_log=${context_single_var}.activity_log.prefetch_user %}
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
13
13
|
{% endblock %}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{% extends 'django_spire/page/form_full_page.html' %}
|
|
2
2
|
|
|
3
|
-
{% block
|
|
3
|
+
{% block full_page_content %}
|
|
4
4
|
<form method="post">
|
|
5
5
|
{% csrf_token %}
|
|
6
6
|
|
|
7
7
|
<div class="row g-3">
|
|
8
8
|
<div class="col-12">
|
|
9
|
-
{% include '${template_directory_path}/card/${form_card_template_name}' %}
|
|
9
|
+
{% include '${template_directory_path}/card/${form_card_template_name}.html' %}
|
|
10
10
|
</div>
|
|
11
11
|
</div>
|
|
12
12
|
</form>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{% extends 'django_spire/page/full_page.html' %}
|
|
2
2
|
|
|
3
|
-
{% block
|
|
3
|
+
{% block full_page_content %}
|
|
4
4
|
<div class="row">
|
|
5
5
|
<div class="col-12">
|
|
6
|
-
{% include '${template_directory_path}/card/${list_card_template_name}' %}
|
|
6
|
+
{% include '${template_directory_path}/card/${list_card_template_name}.html' %}
|
|
7
7
|
</div>
|
|
8
8
|
</div>
|
|
9
9
|
{% endblock %}
|
|
@@ -2,10 +2,13 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
5
|
+
from typing import TYPE_CHECKING, Tuple
|
|
6
6
|
|
|
7
7
|
from django.core.management.base import CommandError
|
|
8
8
|
|
|
9
|
+
from django_spire.core.management.commands.spire_startapp_pkg.exceptions import \
|
|
10
|
+
AppExistsError
|
|
11
|
+
|
|
9
12
|
if TYPE_CHECKING:
|
|
10
13
|
from django_spire.core.management.commands.spire_startapp_pkg.reporter import Reporter
|
|
11
14
|
from django_spire.core.management.commands.spire_startapp_pkg.validator import AppValidator
|
|
@@ -30,6 +33,8 @@ class UserInputCollector:
|
|
|
30
33
|
self.reporter = reporter
|
|
31
34
|
self.validator = validator
|
|
32
35
|
|
|
36
|
+
self.skip_app_creation = False
|
|
37
|
+
|
|
33
38
|
def collect_all_inputs(self) -> dict[str, str]:
|
|
34
39
|
"""
|
|
35
40
|
Collects all required user inputs for app creation.
|
|
@@ -52,13 +57,19 @@ class UserInputCollector:
|
|
|
52
57
|
db_table_name = self._collect_db_table_name(components, app_name) # Changed from app_label to components, app_name
|
|
53
58
|
model_permission_path = self._collect_model_permission_path(app_path, model_name)
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
if not self.skip_app_creation:
|
|
61
|
+
permission_data = self._collect_permission_inheritance(components)
|
|
62
|
+
else:
|
|
63
|
+
permission_data = {}
|
|
64
|
+
|
|
65
|
+
template_options = self._collect_template_generation_options(components)
|
|
56
66
|
|
|
57
67
|
verbose_name, verbose_name_plural = self._derive_verbose_names(model_name, model_name_plural)
|
|
58
68
|
|
|
59
69
|
return {
|
|
60
70
|
'app_path': app_path,
|
|
61
71
|
'app_name': app_name,
|
|
72
|
+
'skip_app_generation': self.skip_app_creation,
|
|
62
73
|
'model_name': model_name,
|
|
63
74
|
'model_name_plural': model_name_plural,
|
|
64
75
|
'app_label': app_label,
|
|
@@ -67,6 +78,7 @@ class UserInputCollector:
|
|
|
67
78
|
'verbose_name': verbose_name,
|
|
68
79
|
'verbose_name_plural': verbose_name_plural,
|
|
69
80
|
**permission_data,
|
|
81
|
+
**template_options
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
def _collect_app_label(self, components: list[str], app_name: str) -> str:
|
|
@@ -79,8 +91,12 @@ class UserInputCollector:
|
|
|
79
91
|
"""
|
|
80
92
|
|
|
81
93
|
immediate_parent = components[-2] if len(components) > 2 else None
|
|
94
|
+
|
|
82
95
|
default = immediate_parent.lower() + '_' + app_name.lower() if immediate_parent else app_name.lower()
|
|
83
|
-
|
|
96
|
+
if self.skip_app_creation:
|
|
97
|
+
return default
|
|
98
|
+
else:
|
|
99
|
+
return self._collect_input('Enter the app label', default, '3/8')
|
|
84
100
|
|
|
85
101
|
def _collect_app_name(self, components: list[str]) -> str:
|
|
86
102
|
"""
|
|
@@ -91,7 +107,10 @@ class UserInputCollector:
|
|
|
91
107
|
"""
|
|
92
108
|
|
|
93
109
|
default = components[-1]
|
|
94
|
-
|
|
110
|
+
if self.skip_app_creation:
|
|
111
|
+
return default
|
|
112
|
+
else:
|
|
113
|
+
return self._collect_input('Enter the app name', default, '2/8')
|
|
95
114
|
|
|
96
115
|
def _collect_app_path(self) -> str:
|
|
97
116
|
"""
|
|
@@ -110,7 +129,12 @@ class UserInputCollector:
|
|
|
110
129
|
raise CommandError(message)
|
|
111
130
|
|
|
112
131
|
components = app_path.split('.')
|
|
113
|
-
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
self.validator.validate_app_path(components)
|
|
135
|
+
except AppExistsError as exc:
|
|
136
|
+
self.reporter.write('\nSkipping app creation.', self.reporter.style_notice)
|
|
137
|
+
self.skip_app_creation = True
|
|
114
138
|
|
|
115
139
|
return app_path
|
|
116
140
|
|
|
@@ -125,7 +149,10 @@ class UserInputCollector:
|
|
|
125
149
|
|
|
126
150
|
parent_parts = components[1:-1] if len(components) > 1 else []
|
|
127
151
|
default = '_'.join(parent_parts).lower() + '_' + app_name.lower() if parent_parts else app_name.lower()
|
|
128
|
-
|
|
152
|
+
if self.skip_app_creation:
|
|
153
|
+
return default
|
|
154
|
+
else:
|
|
155
|
+
return self._collect_input('Enter the database table name', default, '6/8')
|
|
129
156
|
|
|
130
157
|
def _collect_input(self, prompt: str, default: str, step_number: str) -> str:
|
|
131
158
|
"""
|
|
@@ -150,7 +177,10 @@ class UserInputCollector:
|
|
|
150
177
|
"""
|
|
151
178
|
|
|
152
179
|
default = ''.join(word.title() for word in app_name.split('_'))
|
|
153
|
-
|
|
180
|
+
if self.skip_app_creation:
|
|
181
|
+
return default
|
|
182
|
+
else:
|
|
183
|
+
return self._collect_input('Enter the model name', default, '4/8')
|
|
154
184
|
|
|
155
185
|
def _collect_model_name_plural(self, model_name: str) -> str:
|
|
156
186
|
"""
|
|
@@ -161,7 +191,10 @@ class UserInputCollector:
|
|
|
161
191
|
"""
|
|
162
192
|
|
|
163
193
|
default = model_name + 's'
|
|
164
|
-
|
|
194
|
+
if self.skip_app_creation:
|
|
195
|
+
return default
|
|
196
|
+
else:
|
|
197
|
+
return self._collect_input('Enter the model name plural', default, '5/8')
|
|
165
198
|
|
|
166
199
|
def _collect_model_permission_path(self, app_path: str, model_name: str) -> str:
|
|
167
200
|
"""
|
|
@@ -173,7 +206,11 @@ class UserInputCollector:
|
|
|
173
206
|
"""
|
|
174
207
|
|
|
175
208
|
default = f'{app_path}.models.{model_name}'
|
|
176
|
-
|
|
209
|
+
if self.skip_app_creation:
|
|
210
|
+
return default
|
|
211
|
+
else:
|
|
212
|
+
return self._collect_input('Enter the model permission path', default,
|
|
213
|
+
'7/8')
|
|
177
214
|
|
|
178
215
|
def _collect_permission_inheritance(self, components: list[str]) -> dict[str, str]:
|
|
179
216
|
"""
|
|
@@ -253,3 +290,39 @@ class UserInputCollector:
|
|
|
253
290
|
self.reporter.write('\n[8/8]: Do you want this app to inherit permissions from its parent? (y/n)', self.reporter.style_notice)
|
|
254
291
|
user_input = input('Default is "n": ').strip().lower()
|
|
255
292
|
return user_input == 'y'
|
|
293
|
+
|
|
294
|
+
def _collect_template_generation_options(self, components):
|
|
295
|
+
user_input = {}
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
self.validator.validate_template_path(components)
|
|
299
|
+
except AppExistsError:
|
|
300
|
+
user_input['skip_template_generation'] = True
|
|
301
|
+
return user_input
|
|
302
|
+
|
|
303
|
+
self.reporter.write('\n[Template Creation Wizard]\n\n',
|
|
304
|
+
self.reporter.style_success)
|
|
305
|
+
|
|
306
|
+
user_input[
|
|
307
|
+
'skip_template_generation'] = self._collect_skip_template_generation()
|
|
308
|
+
|
|
309
|
+
if not user_input['skip_template_generation']:
|
|
310
|
+
user_input['list_display_type'] = self._collect_input(
|
|
311
|
+
'How do you want to display items on the list page? (items/table)',
|
|
312
|
+
'items',
|
|
313
|
+
'2/2')
|
|
314
|
+
|
|
315
|
+
return user_input
|
|
316
|
+
|
|
317
|
+
def _collect_skip_template_generation(self):
|
|
318
|
+
"""
|
|
319
|
+
Prompts the user to generate templates.
|
|
320
|
+
|
|
321
|
+
:return: True if user wants to skip template generation, False otherwise.
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
user_input = self._collect_input(
|
|
325
|
+
'Do you want to generate templates for this app? (y/n)', 'n',
|
|
326
|
+
'1/2')
|
|
327
|
+
|
|
328
|
+
return user_input == 'n'
|
|
@@ -4,6 +4,9 @@ from typing import TYPE_CHECKING
|
|
|
4
4
|
|
|
5
5
|
from django.core.management.base import CommandError
|
|
6
6
|
|
|
7
|
+
from django_spire.core.management.commands.spire_startapp_pkg.exceptions import \
|
|
8
|
+
AppExistsError
|
|
9
|
+
|
|
7
10
|
if TYPE_CHECKING:
|
|
8
11
|
from django_spire.core.management.commands.spire_startapp_pkg.filesystem import FileSystem
|
|
9
12
|
from django_spire.core.management.commands.spire_startapp_pkg.registry import AppRegistry
|
|
@@ -65,14 +68,24 @@ class AppValidator:
|
|
|
65
68
|
destination = self._path_resolver.get_app_destination(components)
|
|
66
69
|
|
|
67
70
|
if self._filesystem.has_content(destination):
|
|
68
|
-
|
|
71
|
+
message = f'The app already exists at {destination}.'
|
|
72
|
+
self._reporter.write(f'\n{message}', self._reporter.style_notice)
|
|
73
|
+
raise AppExistsError(message)
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
75
|
+
def validate_template_path(self, components: list[str]) -> None:
|
|
76
|
+
"""
|
|
77
|
+
Validates that an app's template path doesn't already exist.
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
:param components: List of app path components.
|
|
80
|
+
:raises CommandError: If an app already exists at the destination path.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
destination = self._path_resolver.get_template_destination(components)
|
|
84
|
+
|
|
85
|
+
if self._filesystem.has_content(destination):
|
|
86
|
+
message = f'App templates already exists at {destination}.'
|
|
87
|
+
self._reporter.write(f'\n{message}', self._reporter.style_notice)
|
|
88
|
+
raise AppExistsError(message)
|
|
76
89
|
|
|
77
90
|
def validate_root_app(self, components: list[str]) -> None:
|
|
78
91
|
"""
|
django_spire/core/middleware.py
CHANGED
|
@@ -7,9 +7,8 @@ from typing import TYPE_CHECKING, Callable
|
|
|
7
7
|
|
|
8
8
|
# from django_spire.consts import MAINTENANCE_MODE_SETTINGS_NAME
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from django.http import HttpResponse
|
|
10
|
+
from django.core.handlers.wsgi import WSGIRequest
|
|
11
|
+
from django.http import HttpResponse
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class MaintenanceMiddleware:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from django.db.models import QuerySet, Q
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SearchQuerySetMixin:
|
|
5
|
+
def search(self, search_value: str) -> QuerySet:
|
|
6
|
+
words = search_value.split(' ')
|
|
7
|
+
|
|
8
|
+
filtered_query = self
|
|
9
|
+
|
|
10
|
+
char_fields = [
|
|
11
|
+
field.name for field in self.model._meta.fields
|
|
12
|
+
if field.get_internal_type() == 'CharField'
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
for word in words:
|
|
16
|
+
or_conditions = Q()
|
|
17
|
+
for field in char_fields:
|
|
18
|
+
or_conditions |= Q(**{f"{field}__icontains": word})
|
|
19
|
+
filtered_query = filtered_query.filter(or_conditions)
|
|
@@ -247,16 +247,19 @@ window.get_echarts_theme = function() {
|
|
|
247
247
|
let is_dark = document.documentElement.getAttribute('data-theme') === 'dark';
|
|
248
248
|
|
|
249
249
|
return {
|
|
250
|
-
text: styles.getPropertyValue('--app-default-text-color').trim(),
|
|
251
|
-
primary: styles.getPropertyValue('--app-primary').trim(),
|
|
252
|
-
primary_dark: styles.getPropertyValue('--app-primary-dark').trim(),
|
|
253
|
-
secondary: styles.getPropertyValue('--app-secondary').trim(),
|
|
254
|
-
secondary_dark: styles.getPropertyValue('--app-secondary-dark').trim(),
|
|
255
|
-
border: styles.getPropertyValue('--bs-border-color').trim(),
|
|
256
250
|
bg: styles.getPropertyValue('--app-layer-one').trim(),
|
|
251
|
+
border: styles.getPropertyValue('--bs-border-color').trim(),
|
|
252
|
+
danger: styles.getPropertyValue('--app-danger').trim(),
|
|
253
|
+
is_dark: is_dark,
|
|
257
254
|
layer_two: styles.getPropertyValue('--app-layer-two').trim(),
|
|
258
255
|
layer_three: styles.getPropertyValue('--app-layer-three').trim(),
|
|
259
256
|
layer_four: styles.getPropertyValue('--app-layer-four').trim(),
|
|
260
|
-
|
|
257
|
+
primary: styles.getPropertyValue('--app-primary').trim(),
|
|
258
|
+
primary_dark: styles.getPropertyValue('--app-primary-dark').trim(),
|
|
259
|
+
secondary: styles.getPropertyValue('--app-secondary').trim(),
|
|
260
|
+
secondary_dark: styles.getPropertyValue('--app-secondary-dark').trim(),
|
|
261
|
+
success: styles.getPropertyValue('--app-success').trim(),
|
|
262
|
+
text: styles.getPropertyValue('--app-default-text-color').trim(),
|
|
263
|
+
warning: styles.getPropertyValue('--app-warning').trim(),
|
|
261
264
|
};
|
|
262
265
|
};
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
path: '{{ DJANGO_SPIRE_THEME_PATH|escapejs }}'
|
|
43
43
|
};
|
|
44
44
|
</script>
|
|
45
|
+
<link rel="manifest" href="{% static 'django_spire/favicons/manifest.json' %}">
|
|
45
46
|
|
|
46
47
|
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
|
47
48
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.x/dist/echarts.min.js"></script>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<a
|
|
2
2
|
class="btn shadow-sm {% block button_class %}{% endblock %} {{ button_class|default:'btn-sm' }}"
|
|
3
3
|
{% block button_attributes %}{% endblock %}
|
|
4
|
+
{{ button_attributes }}
|
|
4
5
|
{% if button_href %}href="{{ button_href }}{{ button_url_params }}"{% endif %}
|
|
5
|
-
{% if x_button_click %}@click="{{ x_button_click }}"{% endif %}
|
|
6
|
+
{% if x_button_click or button_modal_href %}@click="{% if button_modal_href %}dispatch_modal_view('{{ button_modal_href }}'){% else %}{{ x_button_click }}{% endif %}"{% endif %}
|
|
6
7
|
>
|
|
7
8
|
{% if button_icon %}
|
|
8
9
|
<i class="{{ button_icon }}"></i>
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
{% block card_body_style %}display: flex; flex-direction: column; min-height: 0;{% endblock %}
|
|
8
8
|
|
|
9
9
|
{% block card_content %}
|
|
10
|
-
<div
|
|
10
|
+
<{% block card_title_content_container_element_type %}div{% endblock %}
|
|
11
|
+
{% block card_title_content_container_attributes %}{% endblock %}
|
|
11
12
|
class="d-flex flex-column flex-grow-1"
|
|
12
13
|
style="min-height: 0;"
|
|
13
14
|
x-data="{
|
|
@@ -17,17 +18,19 @@
|
|
|
17
18
|
}
|
|
18
19
|
}"
|
|
19
20
|
>
|
|
20
|
-
|
|
21
|
-
<div class="
|
|
22
|
-
<div class="
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
{% block card_title_header_content %}
|
|
22
|
+
<div class="row justify-content-between align-items-center mb-2 pb-2 border-bottom flex-shrink-0" style="min-height: 38px;">
|
|
23
|
+
<div class="col d-flex align-items-center">
|
|
24
|
+
<div class="card-title text-uppercase mb-0">
|
|
25
|
+
{% block card_title %}
|
|
26
|
+
{% endblock %}
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="{% block card_button_col_class %}col-auto{% endblock %} d-flex">
|
|
30
|
+
{% block card_button %}{% endblock %}
|
|
25
31
|
</div>
|
|
26
32
|
</div>
|
|
27
|
-
|
|
28
|
-
{% block card_button %}{% endblock %}
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
33
|
+
{% endblock %}
|
|
31
34
|
<div x-show="card_title_dropdown" x-cloak x-collapse class="flex-shrink-0">
|
|
32
35
|
{% block card_dropdown_content %}
|
|
33
36
|
{% endblock %}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="col-12">
|
|
3
3
|
<div class="row justify-content-between align-items-end px-md-3 py-2">
|
|
4
4
|
<div class="col">
|
|
5
|
-
<h1 class="fs-1 fw-semi-bold">
|
|
5
|
+
<h1 class="{% block container_title_class %}fs-1 fw-semi-bold{% endblock %}">
|
|
6
6
|
{% block container_title %}
|
|
7
7
|
{% endblock %}
|
|
8
8
|
</h1>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<form
|
|
2
2
|
method="get"
|
|
3
3
|
action="{% block session_filter_url %}{% endblock %}"
|
|
4
|
-
class="row border-bottom"
|
|
4
|
+
class="{% block form_class %}row border-bottom{% endblock %}"
|
|
5
5
|
>
|
|
6
6
|
<div class="col-12">
|
|
7
7
|
<input type="text" hidden value="{% block session_filter_key %}{% endblock %}" name="session_filter_key">
|