django-spire 0.18.2__py3-none-any.whl → 0.19.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/admin.py +1 -0
- django_spire/ai/chat/apps.py +1 -8
- django_spire/ai/chat/intelligence/decoders/tools.py +29 -0
- django_spire/ai/chat/intelligence/prompts.py +13 -7
- django_spire/ai/chat/intelligence/workflows/chat_workflow.py +40 -52
- django_spire/ai/chat/models.py +2 -1
- django_spire/ai/chat/querysets.py +1 -3
- django_spire/ai/chat/responses.py +5 -0
- django_spire/ai/chat/templates/django_spire/ai/chat/card/chat_card.html +2 -2
- django_spire/ai/chat/templates/django_spire/ai/chat/dropdown/ellipsis_dropdown.html +1 -1
- django_spire/ai/chat/templates/django_spire/ai/chat/element/recent_chat_select_element.html +82 -44
- django_spire/ai/chat/templates/django_spire/ai/chat/message/loading_response_message.html +8 -3
- django_spire/ai/chat/templates/django_spire/ai/chat/message/message.html +16 -7
- django_spire/ai/chat/templates/django_spire/ai/chat/message/request_message.html +5 -8
- django_spire/ai/chat/templates/django_spire/ai/chat/message/response_message.html +14 -10
- django_spire/ai/chat/templates/django_spire/ai/chat/page/chat_page.html +35 -0
- django_spire/ai/chat/templates/django_spire/ai/chat/widget/dialog_widget.html +72 -23
- django_spire/ai/chat/templates/django_spire/ai/chat/widget/selection_widget.html +42 -0
- django_spire/ai/chat/tests/test_urls/test_json_urls.py +4 -2
- django_spire/ai/chat/urls/__init__.py +1 -1
- django_spire/ai/chat/urls/json_urls.py +1 -1
- django_spire/ai/chat/urls/page_urls.py +1 -1
- django_spire/ai/chat/urls/{template_urls.py → template/template_urls.py} +1 -1
- django_spire/ai/chat/views/json_views.py +4 -3
- django_spire/ai/chat/views/message_request_views.py +32 -14
- django_spire/ai/chat/views/message_response_views.py +14 -11
- django_spire/ai/chat/views/message_views.py +7 -1
- django_spire/ai/chat/views/page_views.py +2 -2
- django_spire/ai/chat/views/{template_views.py → template/template_views.py} +1 -7
- django_spire/ai/context/__init__.py +0 -0
- django_spire/ai/context/admin.py +15 -0
- django_spire/ai/context/apps.py +16 -0
- django_spire/ai/context/choices.py +11 -0
- django_spire/ai/context/intelligence/__init__.py +0 -0
- django_spire/ai/context/intelligence/prompts/__init__.py +0 -0
- django_spire/ai/context/intelligence/prompts/organization_prompts.py +19 -0
- django_spire/ai/context/migrations/0001_initial.py +67 -0
- django_spire/ai/context/migrations/__init__.py +0 -0
- django_spire/ai/context/models.py +67 -0
- django_spire/ai/context/querysets.py +15 -0
- django_spire/ai/context/seeding/__init__.py +0 -0
- django_spire/ai/context/seeding/seed.py +24 -0
- django_spire/ai/prompt/system/bots.py +3 -5
- django_spire/ai/prompt/tuning/bots.py +5 -10
- django_spire/ai/sms/admin.py +2 -0
- django_spire/ai/sms/apps.py +2 -7
- django_spire/ai/sms/decorators.py +2 -2
- django_spire/ai/sms/intelligence/workflows/sms_conversation_workflow.py +18 -18
- django_spire/ai/sms/tests/test_webhook.py +5 -4
- django_spire/ai/sms/urls.py +3 -0
- django_spire/ai/sms/views.py +3 -5
- django_spire/ai/urls.py +2 -0
- django_spire/auth/templates/django_spire/auth/form/login_form.html +25 -0
- django_spire/auth/templates/django_spire/auth/page/auth_page.html +2 -3
- django_spire/auth/templates/django_spire/auth/page/login_page.html +1 -25
- django_spire/conf.py +1 -3
- django_spire/consts.py +1 -7
- django_spire/contrib/seeding/intelligence/bots/seeder_generator_bot.py +3 -2
- django_spire/contrib/utils.py +2 -0
- django_spire/core/static/django_spire/css/app-button.css +11 -1
- django_spire/core/static/django_spire/css/app-import.css +2 -0
- django_spire/core/static/django_spire/css/app-layout.css +15 -0
- django_spire/core/static/django_spire/css/app-navigation.css +24 -2
- django_spire/core/static/django_spire/css/app-page.css +8 -0
- django_spire/core/static/django_spire/css/app-side-panel.css +102 -0
- django_spire/core/static/django_spire/css/app-text.css +19 -1
- django_spire/core/static/django_spire/css/bootstrap-extension.css +128 -7
- django_spire/core/static/django_spire/css/bootstrap-override.css +161 -111
- django_spire/core/static/django_spire/css/themes/ayu/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/ayu/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/catppuccin/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/catppuccin/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/default/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/default/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/dracula/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/dracula/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/gruvbox/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/gruvbox/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/material/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/material/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/nord/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/nord/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/oceanic-next/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/oceanic-next/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/one-dark/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/one-dark/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/palenight/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/palenight/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/rose-pine/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/rose-pine/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/synthwave/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/synthwave/app-light.css +0 -4
- django_spire/core/static/django_spire/css/themes/tokyo-night/app-dark.css +0 -4
- django_spire/core/static/django_spire/css/themes/tokyo-night/app-light.css +0 -4
- django_spire/core/static/django_spire/font/Poppins-Black.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-BlackItalic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-Bold.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-BoldItalic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-ExtraBold.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-ExtraBoldItalic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-ExtraLight.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-ExtraLightItalic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-Italic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-Light.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-LightItalic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-Medium.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-MediumItalic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-SemiBold.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-SemiBoldItalic.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-Thin.ttf +0 -0
- django_spire/core/static/django_spire/font/Poppins-ThinItalic.ttf +0 -0
- django_spire/core/static/django_spire/js/ui.js +12 -0
- django_spire/core/templates/django_spire/button/base_button.html +1 -1
- django_spire/core/templates/django_spire/button/primary_dark_outlined_button.html +3 -0
- django_spire/core/templates/django_spire/dropdown/element/dropdown_link_element.html +12 -8
- django_spire/core/templates/django_spire/dropdown/element/ellipsis_dropdown_modal_link_element.html +2 -1
- django_spire/core/templates/django_spire/dropdown/ellipsis_dropdown.html +2 -1
- django_spire/core/templates/django_spire/navigation/accordion/nav_accordion.html +1 -1
- django_spire/core/templates/django_spire/navigation/elements/nav_link.html +1 -1
- django_spire/core/templates/django_spire/navigation/elements/nav_title_divider.html +1 -1
- django_spire/core/templates/django_spire/navigation/side_navigation.html +52 -8
- django_spire/core/templates/django_spire/navigation/top_navigation.html +8 -2
- django_spire/core/templates/django_spire/page/full_page.html +218 -11
- django_spire/core/utils.py +26 -2
- django_spire/knowledge/collection/models.py +24 -0
- django_spire/knowledge/collection/services/transformation_service.py +2 -1
- django_spire/knowledge/collection/tests/test_services/test_transformation_service.py +44 -42
- django_spire/knowledge/collection/urls/form_urls.py +1 -0
- django_spire/knowledge/collection/urls/page_urls.py +1 -0
- django_spire/knowledge/collection/views/form_views.py +13 -2
- django_spire/knowledge/collection/views/page_views.py +36 -4
- django_spire/knowledge/entry/models.py +32 -0
- django_spire/knowledge/entry/services/transformation_services.py +10 -10
- django_spire/knowledge/entry/version/block/data/data.py +2 -1
- django_spire/knowledge/entry/version/block/data/heading_data.py +2 -2
- django_spire/knowledge/entry/version/block/data/list/data.py +3 -4
- django_spire/knowledge/entry/version/block/data/maps.py +3 -5
- django_spire/knowledge/entry/version/block/data/text_data.py +2 -2
- django_spire/knowledge/entry/version/block/models.py +10 -7
- django_spire/knowledge/entry/version/block/services/factory_service.py +11 -10
- django_spire/knowledge/entry/version/block/tests/factories.py +6 -5
- django_spire/knowledge/entry/version/converters/docx_converter.py +2 -4
- django_spire/knowledge/entry/version/intelligence/bots/markdown_format_llm_bot.py +16 -12
- django_spire/knowledge/entry/version/seeding/seeder.py +3 -3
- django_spire/knowledge/entry/version/services/processor_service.py +36 -10
- django_spire/knowledge/entry/version/tests/test_converters/test_docx_converter.py +1 -1
- django_spire/knowledge/entry/version/tests/test_urls/test_page_urls.py +1 -1
- django_spire/knowledge/entry/version/urls/page_urls.py +1 -1
- django_spire/knowledge/entry/version/views/json_views.py +5 -3
- django_spire/knowledge/entry/version/views/page_views.py +11 -12
- django_spire/knowledge/entry/version/views/redirect_views.py +1 -1
- django_spire/knowledge/entry/views/form_views.py +1 -1
- django_spire/knowledge/intelligence/bots/entry_search_llm_bot.py +33 -11
- django_spire/knowledge/intelligence/decoders/__init__.py +0 -0
- django_spire/knowledge/intelligence/{maps/collection_map.py → decoders/collection_decoder.py} +5 -5
- django_spire/knowledge/intelligence/{maps/entry_map.py → decoders/entry_decoder.py} +3 -3
- django_spire/knowledge/intelligence/intel/collection_intel.py +1 -0
- django_spire/knowledge/intelligence/intel/entry_intel.py +5 -2
- django_spire/knowledge/intelligence/intel/message_intel.py +2 -0
- django_spire/knowledge/intelligence/workflows/knowledge_workflow.py +43 -51
- django_spire/knowledge/migrations/0007_alter_collection_options.py +17 -0
- django_spire/knowledge/static/django_spire/knowledge/entry/version/js/editor.js +24 -5
- django_spire/knowledge/templates/django_spire/knowledge/collection/card/top_level_list_card.html +21 -0
- django_spire/knowledge/templates/django_spire/knowledge/collection/component/x_collection_navigation.html +15 -6
- django_spire/knowledge/templates/django_spire/knowledge/collection/element/ellipsis_dropdown.html +22 -0
- django_spire/knowledge/templates/django_spire/knowledge/collection/form/form.html +21 -9
- django_spire/knowledge/templates/django_spire/knowledge/collection/item/collection_item.html +19 -0
- django_spire/knowledge/templates/django_spire/knowledge/collection/page/display_page.html +49 -0
- django_spire/knowledge/templates/django_spire/knowledge/collection/page/form_page.html +1 -1
- django_spire/knowledge/templates/django_spire/knowledge/container/container.html +33 -0
- django_spire/knowledge/templates/django_spire/knowledge/entry/file/page/list_page.html +1 -1
- django_spire/knowledge/templates/django_spire/knowledge/entry/item/list_item.html +2 -2
- django_spire/knowledge/templates/django_spire/knowledge/entry/page/form_page.html +1 -1
- django_spire/knowledge/templates/django_spire/knowledge/entry/page/import_form_page.html +1 -1
- django_spire/knowledge/templates/django_spire/knowledge/entry/version/container/detail_container.html +51 -45
- django_spire/knowledge/templates/django_spire/knowledge/entry/version/page/editor_page.html +54 -0
- django_spire/knowledge/templates/django_spire/knowledge/entry/version/page/form_page.html +1 -1
- django_spire/knowledge/templates/django_spire/knowledge/message/knowledge_message_intel.html +18 -1
- django_spire/knowledge/templates/django_spire/knowledge/page/full_page.html +37 -0
- django_spire/knowledge/templates/django_spire/knowledge/page/home_page.html +2 -2
- django_spire/knowledge/templates/django_spire/knowledge/sub_navigation/item/collection_sub_navigation_item.html +29 -0
- django_spire/knowledge/templates/django_spire/knowledge/sub_navigation/item/entry_sub_navigation_item.html +20 -0
- django_spire/knowledge/templates/django_spire/knowledge/{navigation/content/navigation_content.html → sub_navigation/widget/collection_entry_sub_navigation_widget.html} +42 -19
- django_spire/knowledge/views/page_views.py +4 -4
- django_spire/settings.py +3 -3
- django_spire/theme/templates/django_spire/theme/card/badges_preview_card.html +0 -1
- django_spire/theme/templates/django_spire/theme/card/base_preview_card.html +1 -0
- django_spire/theme/templates/django_spire/theme/card/typography_preview_card.html +1 -1
- django_spire/theme/templates/django_spire/theme/example/form/example_form.html +2 -0
- django_spire/theme/templates/django_spire/theme/example/form/example_form_card.html +5 -0
- django_spire/theme/templates/django_spire/theme/page/badges_page.html +7 -9
- django_spire/theme/templates/django_spire/theme/page/borders_page.html +6 -9
- django_spire/theme/templates/django_spire/theme/page/buttons_page.html +6 -9
- django_spire/theme/templates/django_spire/theme/page/colors_page.html +6 -6
- django_spire/theme/templates/django_spire/theme/page/dashboard_page.html +57 -0
- django_spire/theme/templates/django_spire/theme/page/django_glue_page.html +7 -9
- django_spire/theme/templates/django_spire/theme/page/theme_page.html +24 -0
- django_spire/theme/templates/django_spire/theme/page/typography_page.html +6 -9
- django_spire/theme/templates/django_spire/theme/section/badge_section_card.html +5 -0
- django_spire/theme/templates/django_spire/theme/section/border_section_card.html +5 -0
- django_spire/theme/templates/django_spire/theme/section/button_section.html +1 -0
- django_spire/theme/templates/django_spire/theme/section/button_section_card.html +5 -0
- django_spire/theme/templates/django_spire/theme/section/color_section.html +10 -10
- django_spire/theme/templates/django_spire/theme/section/color_section_card.html +5 -0
- django_spire/theme/templates/django_spire/theme/section/typography_section.html +41 -1
- django_spire/theme/templates/django_spire/theme/section/typography_section_card.html +5 -0
- {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/METADATA +3 -3
- {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/RECORD +217 -178
- django_spire/ai/chat/intelligence/bots/chat_bot.py +0 -8
- django_spire/ai/chat/intelligence/maps/intent_llm_map.py +0 -10
- django_spire/ai/chat/templates/django_spire/ai/chat/page/home_page.html +0 -9
- django_spire/ai/chat/templates/django_spire/ai/chat/widget/chat_widget.html +0 -64
- django_spire/ai/chat/templates/django_spire/ai/chat/widget/search_chat_results_widget.html +0 -25
- django_spire/ai/chat/templates/django_spire/ai/chat/widget/search_chat_widget.html +0 -39
- django_spire/ai/chat/templates/django_spire/ai/chat/widget/select_chat_widget.html +0 -24
- django_spire/ai/chat/tools.py +0 -57
- django_spire/ai/sms/tools.py +0 -57
- django_spire/core/static/django_spire/font/Karla-Bold.ttf +0 -0
- django_spire/core/static/django_spire/font/Merriweather.ttf +0 -0
- django_spire/knowledge/context_processors.py +0 -18
- django_spire/knowledge/templates/django_spire/knowledge/entry/version/page/detail_page.html +0 -25
- django_spire/knowledge/templates/django_spire/knowledge/navigation/card/navigation_card.html +0 -9
- django_spire/knowledge/templates/django_spire/knowledge/navigation/item/collection/collection_item.html +0 -29
- django_spire/knowledge/templates/django_spire/knowledge/navigation/item/entry/entry_item.html +0 -18
- django_spire/knowledge/templates/django_spire/knowledge/navigation/page/full_page.html +0 -90
- /django_spire/ai/chat/intelligence/{bots → decoders}/__init__.py +0 -0
- /django_spire/ai/chat/{intelligence/maps → urls/template}/__init__.py +0 -0
- /django_spire/{knowledge/intelligence/maps → ai/chat/views/template}/__init__.py +0 -0
- /django_spire/knowledge/entry/version/{constants.py → consts.py} +0 -0
- /django_spire/knowledge/templates/django_spire/knowledge/{navigation/item/collection/dropdown/navigation_ellipsis_dropdown.html → sub_navigation/element/collection_sub_navigation_ellipsis_dropdown.html} +0 -0
- /django_spire/knowledge/templates/django_spire/knowledge/{navigation/item/entry/dropdown/navigation_ellipsis_dropdown.html → sub_navigation/element/entry_sub_navigation_ellipsis_dropdown.html} +0 -0
- {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/WHEEL +0 -0
- {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/licenses/LICENSE.md +0 -0
- {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.core.exceptions import ValidationError
|
|
4
|
+
from django.db import models
|
|
5
|
+
|
|
6
|
+
from django_spire.ai.context import querysets
|
|
7
|
+
from django_spire.ai.context.choices import PersonRoleChoices
|
|
8
|
+
from django_spire.auth.user.models import AuthUser
|
|
9
|
+
from django_spire.history.mixins import HistoryModelMixin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Organization(HistoryModelMixin):
|
|
13
|
+
name = models.CharField(max_length=255, blank=True, null=True)
|
|
14
|
+
legal_name = models.CharField(max_length=255, blank=True, null=True)
|
|
15
|
+
description = models.TextField(blank=True, null=True)
|
|
16
|
+
sector = models.CharField(max_length=255, blank=True, null=True)
|
|
17
|
+
sub_sector = models.CharField(max_length=255, blank=True, null=True)
|
|
18
|
+
website = models.URLField(max_length=255, blank=True, null=True)
|
|
19
|
+
street_address = models.CharField(max_length=255, blank=True, null=True)
|
|
20
|
+
unit_number = models.CharField(max_length=32, blank=True, null=True)
|
|
21
|
+
city = models.CharField(max_length=255, blank=True, null=True)
|
|
22
|
+
province = models.CharField(max_length=255, blank=True, null=True)
|
|
23
|
+
postal_code = models.CharField(max_length=16, blank=True, null=True)
|
|
24
|
+
country = models.CharField(max_length=255, blank=True, null=True)
|
|
25
|
+
phone = models.CharField(max_length=255, blank=True, null=True)
|
|
26
|
+
email = models.EmailField(max_length=255, blank=True, null=True)
|
|
27
|
+
|
|
28
|
+
objects = querysets.OrganizationQuerySet.as_manager()
|
|
29
|
+
|
|
30
|
+
def save(self, *args, **kwargs) -> None:
|
|
31
|
+
if self.pk is None:
|
|
32
|
+
if self.__class__.objects.exists():
|
|
33
|
+
message = 'Only one AI Organization Context is allowed'
|
|
34
|
+
raise ValidationError(message)
|
|
35
|
+
|
|
36
|
+
return super().save(*args, **kwargs)
|
|
37
|
+
|
|
38
|
+
class Meta:
|
|
39
|
+
db_table = 'django_spire_ai_context_organization'
|
|
40
|
+
verbose_name = 'Organization Context'
|
|
41
|
+
verbose_name_plural = 'Organization Context'
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Person(HistoryModelMixin):
|
|
45
|
+
is_internal_to_organization = models.BooleanField(default=True)
|
|
46
|
+
user = models.ForeignKey(
|
|
47
|
+
AuthUser,
|
|
48
|
+
blank=True,
|
|
49
|
+
null=True,
|
|
50
|
+
on_delete=models.SET_NULL,
|
|
51
|
+
related_name='ai_context_people',
|
|
52
|
+
related_query_name='ai_context_person'
|
|
53
|
+
)
|
|
54
|
+
role = models.CharField(max_length=16, choices=PersonRoleChoices, default=PersonRoleChoices.ADMIN)
|
|
55
|
+
role_details = models.TextField(blank=True, null=True)
|
|
56
|
+
first_name = models.CharField(max_length=255, blank=True, null=True)
|
|
57
|
+
last_name = models.CharField(max_length=255, blank=True, null=True)
|
|
58
|
+
phone = models.CharField(max_length=255, blank=True, null=True)
|
|
59
|
+
email = models.EmailField(max_length=255, blank=True, null=True)
|
|
60
|
+
|
|
61
|
+
objects = querysets.PeopleQuerySet.as_manager()
|
|
62
|
+
|
|
63
|
+
class Meta:
|
|
64
|
+
db_table = 'django_spire_ai_context_person'
|
|
65
|
+
verbose_name = 'Person Context'
|
|
66
|
+
verbose_name_plural = 'People Context'
|
|
67
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django_spire.history.querysets import HistoryQuerySet
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OrganizationQuerySet(HistoryQuerySet):
|
|
7
|
+
def get_only_or_none(self):
|
|
8
|
+
try:
|
|
9
|
+
return self.earliest('id')
|
|
10
|
+
except self.model.DoesNotExist:
|
|
11
|
+
return None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PeopleQuerySet(HistoryQuerySet):
|
|
15
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django_spire.ai.context import models
|
|
4
|
+
from django_spire.ai.context import choices
|
|
5
|
+
|
|
6
|
+
from faker import Faker
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
models.Organization.objects.create(
|
|
10
|
+
name='Spire Candy',
|
|
11
|
+
legal_name='Spire Candy Processors Limited',
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
for people_role_choice in choices.PersonRoleChoices:
|
|
15
|
+
first_name = Faker().first_name()
|
|
16
|
+
last_name = Faker().last_name()
|
|
17
|
+
|
|
18
|
+
people = models.Person.objects.create(
|
|
19
|
+
role=people_role_choice.value,
|
|
20
|
+
first_name=first_name,
|
|
21
|
+
last_name=last_name,
|
|
22
|
+
email=f'{first_name.lower()}.{last_name.lower()}@spirecandy.ca',
|
|
23
|
+
phone=Faker().phone_number(),
|
|
24
|
+
)
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from dandy import Bot, LlmConfigOptions
|
|
3
|
+
from dandy import Bot, LlmConfigOptions
|
|
4
4
|
|
|
5
|
-
from django_spire.ai.prompt.system import prompts
|
|
6
|
-
from django_spire.ai.prompt.system import intel
|
|
7
|
-
from django_spire.ai.prompt.system.intel import SystemPromptIntel
|
|
5
|
+
from django_spire.ai.prompt.system import intel, prompts
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
class RoleSystemPromptBot(Bot):
|
|
@@ -70,7 +68,7 @@ class SystemPromptBot(Bot):
|
|
|
70
68
|
guidelines = guidelines_bot.process(user_story)
|
|
71
69
|
output_format = output_format_bot.process(user_story)
|
|
72
70
|
|
|
73
|
-
return SystemPromptIntel(
|
|
71
|
+
return intel.SystemPromptIntel(
|
|
74
72
|
role=role.result,
|
|
75
73
|
task=task.result,
|
|
76
74
|
guidelines=guidelines.result,
|
|
@@ -65,8 +65,7 @@ class FormattingBot(Bot):
|
|
|
65
65
|
def process(self, system_prompt: str) -> intel.PromptTuningIntel:
|
|
66
66
|
return self.llm.prompt_to_intel(
|
|
67
67
|
prompt=prompts.specialized_bot_input_prompt(system_prompt),
|
|
68
|
-
intel_class=intel.PromptTuningIntel
|
|
69
|
-
postfix_system_prompt=None
|
|
68
|
+
intel_class=intel.PromptTuningIntel
|
|
70
69
|
)
|
|
71
70
|
|
|
72
71
|
|
|
@@ -76,8 +75,7 @@ class InstructionClarityBot(Bot):
|
|
|
76
75
|
def process(self, system_prompt: str) -> intel.PromptTuningIntel:
|
|
77
76
|
return self.llm.prompt_to_intel(
|
|
78
77
|
prompt=prompts.specialized_bot_input_prompt(system_prompt),
|
|
79
|
-
intel_class=intel.PromptTuningIntel
|
|
80
|
-
postfix_system_prompt=None
|
|
78
|
+
intel_class=intel.PromptTuningIntel
|
|
81
79
|
)
|
|
82
80
|
|
|
83
81
|
|
|
@@ -87,8 +85,7 @@ class PersonaBot(Bot):
|
|
|
87
85
|
def process(self, system_prompt: str) -> intel.PromptTuningIntel:
|
|
88
86
|
return self.llm.prompt_to_intel(
|
|
89
87
|
prompt=prompts.specialized_bot_input_prompt(system_prompt),
|
|
90
|
-
intel_class=intel.PromptTuningIntel
|
|
91
|
-
postfix_system_prompt=None
|
|
88
|
+
intel_class=intel.PromptTuningIntel
|
|
92
89
|
)
|
|
93
90
|
|
|
94
91
|
|
|
@@ -98,8 +95,7 @@ class DuplicationRemovalBot(Bot):
|
|
|
98
95
|
def process(self, system_prompt: str) -> intel.PromptTuningIntel:
|
|
99
96
|
return self.llm.prompt_to_intel(
|
|
100
97
|
prompt=prompts.specialized_bot_input_prompt(system_prompt),
|
|
101
|
-
intel_class=intel.PromptTuningIntel
|
|
102
|
-
postfix_system_prompt=None
|
|
98
|
+
intel_class=intel.PromptTuningIntel
|
|
103
99
|
)
|
|
104
100
|
|
|
105
101
|
|
|
@@ -109,6 +105,5 @@ class ExampleOptimizationBot(Bot):
|
|
|
109
105
|
def process(self, system_prompt: str) -> intel.PromptTuningIntel:
|
|
110
106
|
return self.llm.prompt_to_intel(
|
|
111
107
|
prompt=prompts.specialized_bot_input_prompt(system_prompt),
|
|
112
|
-
intel_class=intel.PromptTuningIntel
|
|
113
|
-
postfix_system_prompt=None
|
|
108
|
+
intel_class=intel.PromptTuningIntel
|
|
114
109
|
)
|
django_spire/ai/sms/admin.py
CHANGED
|
@@ -25,11 +25,13 @@ class SmsConversationAdmin(admin.ModelAdmin):
|
|
|
25
25
|
|
|
26
26
|
def view_sms_messages_link(self, obj):
|
|
27
27
|
count = obj.messages.count()
|
|
28
|
+
|
|
28
29
|
url = (
|
|
29
30
|
reverse("admin:django_spire_ai_sms_smsmessage_changelist")
|
|
30
31
|
+ "?"
|
|
31
32
|
+ urlencode({"sms_conversation__id": f"{obj.id}"})
|
|
32
33
|
)
|
|
34
|
+
|
|
33
35
|
return format_html('<a href="%s">%s Messages</a>' % (url, count))
|
|
34
36
|
|
|
35
37
|
view_sms_messages_link.short_description = "Messages"
|
django_spire/ai/sms/apps.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from django.apps import AppConfig
|
|
4
|
-
from django.conf import settings
|
|
5
4
|
|
|
6
|
-
from django_spire.consts import AI_SMS_CONVERSATION_WORKFLOW_CLASS_SETTINGS_NAME
|
|
7
5
|
from django_spire.utils import check_required_apps
|
|
8
6
|
|
|
9
7
|
|
|
@@ -12,10 +10,7 @@ class SmsConfig(AppConfig):
|
|
|
12
10
|
name = 'django_spire.ai.sms'
|
|
13
11
|
label = 'django_spire_ai_sms'
|
|
14
12
|
|
|
15
|
-
REQUIRED_APPS = ('django_spire_ai',)
|
|
16
|
-
|
|
17
|
-
def ready(self):
|
|
18
|
-
if not isinstance(getattr(settings, AI_SMS_CONVERSATION_WORKFLOW_CLASS_SETTINGS_NAME), str):
|
|
19
|
-
raise ValueError(f'"{AI_SMS_CONVERSATION_WORKFLOW_CLASS_SETTINGS_NAME}" must be set in the django settings when using "{self.label}".')
|
|
13
|
+
REQUIRED_APPS = ('django_spire_ai', 'django_spire_ai_context')
|
|
20
14
|
|
|
15
|
+
def ready(self) -> None:
|
|
21
16
|
check_required_apps(self.label)
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
3
5
|
from dandy.recorder import recorder_to_html_file
|
|
4
|
-
from dandy.llm.request.message import MessageHistory
|
|
5
|
-
from django.core.handlers.wsgi import WSGIRequest
|
|
6
6
|
|
|
7
|
-
from django_spire.ai.chat.intelligence.workflows.chat_workflow import
|
|
7
|
+
from django_spire.ai.chat.intelligence.workflows.chat_workflow import chat_workflow
|
|
8
8
|
from django_spire.ai.sms.intel import SmsIntel
|
|
9
9
|
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from django.core.handlers.wsgi import WSGIRequest
|
|
12
|
+
from dandy.llm.request.message import MessageHistory
|
|
13
|
+
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
SpireChatWorkflow.process(
|
|
22
|
-
request,
|
|
23
|
-
user_input=user_input,
|
|
24
|
-
message_history=message_history,
|
|
25
|
-
)
|
|
15
|
+
@recorder_to_html_file('spire_ai_sms_conversation_workflow')
|
|
16
|
+
def sms_conversation_workflow(
|
|
17
|
+
request: WSGIRequest, user_input: str, message_history: MessageHistory | None = None, actor: str | None = None
|
|
18
|
+
) -> SmsIntel:
|
|
19
|
+
return SmsIntel(
|
|
20
|
+
body=str(
|
|
21
|
+
chat_workflow(
|
|
22
|
+
request,
|
|
23
|
+
user_input=user_input,
|
|
24
|
+
message_history=message_history,
|
|
26
25
|
)
|
|
27
26
|
)
|
|
27
|
+
)
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from unittest.mock import patch
|
|
2
2
|
|
|
3
|
-
from django.test import TestCase, Client
|
|
4
3
|
from django.urls import reverse
|
|
5
4
|
|
|
6
5
|
from django_spire.ai.sms.models import SmsConversation
|
|
6
|
+
from django_spire.core.tests.test_cases import BaseTestCase
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class SmsWebhookTests(
|
|
9
|
+
class SmsWebhookTests(BaseTestCase):
|
|
10
10
|
def setUp(self):
|
|
11
|
-
|
|
11
|
+
super().setUp()
|
|
12
|
+
|
|
12
13
|
self.webhook_url = reverse('django_spire:ai:sms:webhook')
|
|
13
14
|
|
|
14
15
|
@patch('twilio.request_validator.RequestValidator.validate')
|
|
@@ -34,4 +35,4 @@ class SmsWebhookTests(TestCase):
|
|
|
34
35
|
self.assertEqual(inbound_message.twilio_sid, 'SM123456789')
|
|
35
36
|
|
|
36
37
|
outbound_message = conversation.messages.filter(is_inbound=False).first()
|
|
37
|
-
self.assertTrue(len(outbound_message.body) > 0)
|
|
38
|
+
self.assertTrue(len(outbound_message.body) > 0)
|
django_spire/ai/sms/urls.py
CHANGED
django_spire/ai/sms/views.py
CHANGED
|
@@ -6,8 +6,8 @@ from django.views.decorators.http import require_POST
|
|
|
6
6
|
from twilio.twiml.messaging_response import MessagingResponse
|
|
7
7
|
|
|
8
8
|
from django_spire.ai.sms.decorators import twilio_auth_required
|
|
9
|
+
from django_spire.ai.sms.intelligence.workflows.sms_conversation_workflow import sms_conversation_workflow
|
|
9
10
|
from django_spire.ai.sms.models import SmsConversation
|
|
10
|
-
from django_spire.ai.sms.tools import sms_workflow_process
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@csrf_exempt
|
|
@@ -22,7 +22,7 @@ def webhook_view(request):
|
|
|
22
22
|
body = request.POST.get('Body', '')
|
|
23
23
|
message_sid = request.POST.get('MessageSid', '')
|
|
24
24
|
|
|
25
|
-
conversation,
|
|
25
|
+
conversation, _ = SmsConversation.objects.get_or_create(
|
|
26
26
|
phone_number=from_number
|
|
27
27
|
)
|
|
28
28
|
|
|
@@ -33,8 +33,7 @@ def webhook_view(request):
|
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
try:
|
|
36
|
-
|
|
37
|
-
sms_intel = sms_workflow_process(
|
|
36
|
+
sms_intel = sms_conversation_workflow(
|
|
38
37
|
request=request,
|
|
39
38
|
user_input=body,
|
|
40
39
|
message_history=conversation.generate_message_history(),
|
|
@@ -55,7 +54,6 @@ def webhook_view(request):
|
|
|
55
54
|
message.save()
|
|
56
55
|
|
|
57
56
|
return HttpResponse(twiml_response)
|
|
58
|
-
|
|
59
57
|
except:
|
|
60
58
|
raise
|
|
61
59
|
|
django_spire/ai/urls.py
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<form
|
|
2
|
+
class="text-app-secondary"
|
|
3
|
+
method="post"
|
|
4
|
+
x-data="{
|
|
5
|
+
username: new GlueCharField('username', {required: true, label: {% block username_label %}'Email Address'{% endblock %}}),
|
|
6
|
+
password: new GlueCharField('password', {required: true})
|
|
7
|
+
}"
|
|
8
|
+
>
|
|
9
|
+
{% csrf_token %}
|
|
10
|
+
<div class="row">
|
|
11
|
+
<div class="col">
|
|
12
|
+
{% include 'django_glue/form/field/char_field.html' with glue_field='username' %}
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="row mt-2">
|
|
16
|
+
<div class="col">
|
|
17
|
+
{% include 'django_glue/form/field/password_field.html' with glue_field='password' %}
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="row mt-2">
|
|
21
|
+
<div class="col">
|
|
22
|
+
<button type="submit" class="d-block mx-auto btn btn-app-primary-outlined my-4 w-100">Login</button>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</form>
|
|
@@ -3,15 +3,14 @@
|
|
|
3
3
|
{% load static %}
|
|
4
4
|
|
|
5
5
|
{% block page_content %}
|
|
6
|
-
<div class="row justify-content-center
|
|
6
|
+
<div class="row justify-content-center mx-auto mt-5">
|
|
7
7
|
<div class="col-11 col-md-6 col-lg-4 bg-app-layer-one">
|
|
8
8
|
<div class="px-4 py-5">
|
|
9
9
|
{% block authentication_page_top_content %}
|
|
10
10
|
<div class="text-center pb-5">
|
|
11
11
|
<a href="/">
|
|
12
12
|
{% block authentication_page_img %}
|
|
13
|
-
<img class="ms-1
|
|
14
|
-
alt="">
|
|
13
|
+
<img height="120px" class="ms-1" src="{% static 'img/django_spire.png' %}" alt="">
|
|
15
14
|
{% endblock %}
|
|
16
15
|
</a>
|
|
17
16
|
</div>
|
|
@@ -1,31 +1,7 @@
|
|
|
1
1
|
{% extends 'django_spire/auth/page/auth_page.html' %}
|
|
2
2
|
|
|
3
3
|
{% block authentication_page_content %}
|
|
4
|
-
|
|
5
|
-
class="text-app-secondary"
|
|
6
|
-
method="post"
|
|
7
|
-
x-data="{
|
|
8
|
-
username: new GlueCharField('username', {required: true, label: {% block username_label %}'Email Address'{% endblock %}}),
|
|
9
|
-
password: new GlueCharField('password', {required: true})
|
|
10
|
-
}"
|
|
11
|
-
>
|
|
12
|
-
{% csrf_token %}
|
|
13
|
-
<div class="row">
|
|
14
|
-
<div class="col">
|
|
15
|
-
{% include 'django_glue/form/field/char_field.html' with glue_field='username' %}
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
18
|
-
<div class="row mt-2">
|
|
19
|
-
<div class="col">
|
|
20
|
-
{% include 'django_glue/form/field/password_field.html' with glue_field='password' %}
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
<div class="row mt-2">
|
|
24
|
-
<div class="col">
|
|
25
|
-
<button type="submit" class="d-block mx-auto btn btn-app-primary-outlined my-4 w-100">Login</button>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</form>
|
|
4
|
+
{% include 'django_spire/auth/form/login_form.html' %}
|
|
29
5
|
|
|
30
6
|
<div class="text-center">
|
|
31
7
|
<a href="{% url 'django_spire:auth:admin:password_reset' %}"
|
django_spire/conf.py
CHANGED
django_spire/consts.py
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
__VERSION__ = '0.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
AI_CHAT_WORKFLOW_SENDER_SETTINGS_NAME = 'AI_CHAT_WORKFLOW_NAME'
|
|
5
|
-
AI_CHAT_WORKFLOW_CLASS_SETTINGS_NAME = 'AI_CHAT_WORKFLOW_CLASS'
|
|
6
|
-
AI_SMS_CONVERSATION_WORKFLOW_CLASS_SETTINGS_NAME = 'AI_SMS_CONVERSATION_WORKFLOW_CLASS'
|
|
7
|
-
|
|
1
|
+
__VERSION__ = '0.19.0'
|
|
8
2
|
|
|
9
3
|
MAINTENANCE_MODE_SETTINGS_NAME = 'MAINTENANCE_MODE'
|
|
10
4
|
|
|
@@ -15,6 +15,8 @@ class SeederGeneratorBot(Bot):
|
|
|
15
15
|
randomize_seed=True
|
|
16
16
|
)
|
|
17
17
|
|
|
18
|
+
llm_guidelines = generate_django_model_seeder_system_prompt()
|
|
19
|
+
|
|
18
20
|
llm_role = 'You are an expert Python developer specializing in Django model seeders.'
|
|
19
21
|
|
|
20
22
|
def process(
|
|
@@ -27,6 +29,5 @@ class SeederGeneratorBot(Bot):
|
|
|
27
29
|
model_import,
|
|
28
30
|
model_description,
|
|
29
31
|
),
|
|
30
|
-
intel_class=SourceIntel
|
|
31
|
-
postfix_system_prompt=generate_django_model_seeder_system_prompt()
|
|
32
|
+
intel_class=SourceIntel
|
|
32
33
|
)
|
|
@@ -67,11 +67,21 @@
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
.btn-app-primary-outlined {
|
|
70
|
+
color: var(--app-btn-primary) !important;
|
|
71
|
+
border: 1px solid var(--app-btn-primary) !important;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.btn-app-primary-outlined:hover {
|
|
75
|
+
background-color: var(--app-btn-primary) !important;
|
|
76
|
+
color: var(--app-default-button-text-color) !important;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.btn-app-primary-dark-outlined {
|
|
70
80
|
color: var(--app-btn-primary-dark) !important;
|
|
71
81
|
border: 1px solid var(--app-btn-primary-dark) !important;
|
|
72
82
|
}
|
|
73
83
|
|
|
74
|
-
.btn-app-primary-outlined:hover {
|
|
84
|
+
.btn-app-primary-dark-outlined:hover {
|
|
75
85
|
background-color: var(--app-btn-primary-dark) !important;
|
|
76
86
|
color: var(--app-default-button-text-color) !important;
|
|
77
87
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@import url('app-default.css');
|
|
2
|
+
@import url('app-layout.css');
|
|
2
3
|
@import url('app-theme.css');
|
|
3
4
|
@import url('app-background.css');
|
|
4
5
|
@import url('app-border.css');
|
|
@@ -6,5 +7,6 @@
|
|
|
6
7
|
@import url('app-offcanvas.css');
|
|
7
8
|
@import url('app-navigation.css');
|
|
8
9
|
@import url('app-page.css');
|
|
10
|
+
@import url('app-side-panel.css');
|
|
9
11
|
@import url('app-text.css');
|
|
10
12
|
@import url('app-template.css');
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--app-footer-height: 70px;
|
|
3
|
+
--app-mobile-navigation-width: 250px;
|
|
4
|
+
--app-side-navigation-width: 250px;
|
|
5
|
+
--app-side-navigation-top-content-height: 230px;
|
|
6
|
+
--app-top-navigation-height: 80px;
|
|
7
|
+
|
|
8
|
+
--app-content-height: calc(100vh - var(--app-top-navigation-height) );
|
|
9
|
+
--app-side-panel-height: calc(100vh - var(--app-top-navigation-height) - 1vh);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.vh-minus-top-nav {
|
|
13
|
+
height: calc(100vh - var(--app-top-navigation-height));
|
|
14
|
+
}
|
|
15
|
+
|
|
@@ -39,6 +39,11 @@
|
|
|
39
39
|
color: var(--app-footer-link-hover-color) !important;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
.navbar-nav-scroll {
|
|
43
|
+
max-height: calc(100vh - 120px);
|
|
44
|
+
overflow-y: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
.top-navigation {
|
|
43
48
|
background-color: var(--app-top-navigation-bg-color) !important;
|
|
44
49
|
color: var(--app-top-navigation-text-color) !important;
|
|
@@ -52,22 +57,39 @@
|
|
|
52
57
|
color: var(--app-top-navigation-link-hover-color) !important;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
/* Must be below top-navigation for mobile side navigation css to be correct */
|
|
56
60
|
.side-navigation {
|
|
57
61
|
background-color: var(--app-side-navigation-bg-color) !important;
|
|
62
|
+
border-color: var(--bs-border-color);
|
|
63
|
+
border-right-style: solid;
|
|
64
|
+
border-right-width: 1px;
|
|
58
65
|
color: var(--app-side-navigation-text-color) !important;
|
|
59
66
|
width: var(--app-side-navigation-width);
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
.side-navigation a {
|
|
63
70
|
color: var(--app-side-navigation-link-color) !important;
|
|
71
|
+
display: block;
|
|
72
|
+
padding: 0.75rem 1rem;
|
|
73
|
+
transition: background-color 0.2s ease, color 0.2s ease;
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
.side-navigation a:hover {
|
|
67
77
|
color: var(--app-side-navigation-link-hover-color) !important;
|
|
68
78
|
}
|
|
69
79
|
|
|
70
|
-
.
|
|
80
|
+
.side-navigation-fade-bottom {
|
|
81
|
+
background: linear-gradient(to top, var(--app-side-navigation-bg-color) 0%, var(--app-side-navigation-bg-color) 50%, transparent 100%);
|
|
82
|
+
height: 100px;
|
|
83
|
+
pointer-events: none;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.side-navigation-fade-top {
|
|
87
|
+
background: linear-gradient(to bottom, var(--app-side-navigation-bg-color) 0%, var(--app-side-navigation-bg-color) 50%, transparent 100%);
|
|
88
|
+
height: 75px;
|
|
89
|
+
pointer-events: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.vh-minus-top-nav {
|
|
71
93
|
height: calc(100vh - var(--app-top-navigation-height));
|
|
72
94
|
}
|
|
73
95
|
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
width: 100%;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
+
.main-content-with-panels {
|
|
6
|
+
transition: margin-left 0.3s ease, margin-right 0.3s ease;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.main-content-with-panels.with-left-panel {
|
|
10
|
+
margin-left: calc(var(--app-side-panel-width) * 0.5);
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
@media (min-width: 992px) {
|
|
6
14
|
.full-page-content {
|
|
7
15
|
width: calc(100% - var(--app-side-navigation-width));
|