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.
Files changed (234) hide show
  1. django_spire/ai/admin.py +1 -0
  2. django_spire/ai/chat/apps.py +1 -8
  3. django_spire/ai/chat/intelligence/decoders/tools.py +29 -0
  4. django_spire/ai/chat/intelligence/prompts.py +13 -7
  5. django_spire/ai/chat/intelligence/workflows/chat_workflow.py +40 -52
  6. django_spire/ai/chat/models.py +2 -1
  7. django_spire/ai/chat/querysets.py +1 -3
  8. django_spire/ai/chat/responses.py +5 -0
  9. django_spire/ai/chat/templates/django_spire/ai/chat/card/chat_card.html +2 -2
  10. django_spire/ai/chat/templates/django_spire/ai/chat/dropdown/ellipsis_dropdown.html +1 -1
  11. django_spire/ai/chat/templates/django_spire/ai/chat/element/recent_chat_select_element.html +82 -44
  12. django_spire/ai/chat/templates/django_spire/ai/chat/message/loading_response_message.html +8 -3
  13. django_spire/ai/chat/templates/django_spire/ai/chat/message/message.html +16 -7
  14. django_spire/ai/chat/templates/django_spire/ai/chat/message/request_message.html +5 -8
  15. django_spire/ai/chat/templates/django_spire/ai/chat/message/response_message.html +14 -10
  16. django_spire/ai/chat/templates/django_spire/ai/chat/page/chat_page.html +35 -0
  17. django_spire/ai/chat/templates/django_spire/ai/chat/widget/dialog_widget.html +72 -23
  18. django_spire/ai/chat/templates/django_spire/ai/chat/widget/selection_widget.html +42 -0
  19. django_spire/ai/chat/tests/test_urls/test_json_urls.py +4 -2
  20. django_spire/ai/chat/urls/__init__.py +1 -1
  21. django_spire/ai/chat/urls/json_urls.py +1 -1
  22. django_spire/ai/chat/urls/page_urls.py +1 -1
  23. django_spire/ai/chat/urls/{template_urls.py → template/template_urls.py} +1 -1
  24. django_spire/ai/chat/views/json_views.py +4 -3
  25. django_spire/ai/chat/views/message_request_views.py +32 -14
  26. django_spire/ai/chat/views/message_response_views.py +14 -11
  27. django_spire/ai/chat/views/message_views.py +7 -1
  28. django_spire/ai/chat/views/page_views.py +2 -2
  29. django_spire/ai/chat/views/{template_views.py → template/template_views.py} +1 -7
  30. django_spire/ai/context/__init__.py +0 -0
  31. django_spire/ai/context/admin.py +15 -0
  32. django_spire/ai/context/apps.py +16 -0
  33. django_spire/ai/context/choices.py +11 -0
  34. django_spire/ai/context/intelligence/__init__.py +0 -0
  35. django_spire/ai/context/intelligence/prompts/__init__.py +0 -0
  36. django_spire/ai/context/intelligence/prompts/organization_prompts.py +19 -0
  37. django_spire/ai/context/migrations/0001_initial.py +67 -0
  38. django_spire/ai/context/migrations/__init__.py +0 -0
  39. django_spire/ai/context/models.py +67 -0
  40. django_spire/ai/context/querysets.py +15 -0
  41. django_spire/ai/context/seeding/__init__.py +0 -0
  42. django_spire/ai/context/seeding/seed.py +24 -0
  43. django_spire/ai/prompt/system/bots.py +3 -5
  44. django_spire/ai/prompt/tuning/bots.py +5 -10
  45. django_spire/ai/sms/admin.py +2 -0
  46. django_spire/ai/sms/apps.py +2 -7
  47. django_spire/ai/sms/decorators.py +2 -2
  48. django_spire/ai/sms/intelligence/workflows/sms_conversation_workflow.py +18 -18
  49. django_spire/ai/sms/tests/test_webhook.py +5 -4
  50. django_spire/ai/sms/urls.py +3 -0
  51. django_spire/ai/sms/views.py +3 -5
  52. django_spire/ai/urls.py +2 -0
  53. django_spire/auth/templates/django_spire/auth/form/login_form.html +25 -0
  54. django_spire/auth/templates/django_spire/auth/page/auth_page.html +2 -3
  55. django_spire/auth/templates/django_spire/auth/page/login_page.html +1 -25
  56. django_spire/conf.py +1 -3
  57. django_spire/consts.py +1 -7
  58. django_spire/contrib/seeding/intelligence/bots/seeder_generator_bot.py +3 -2
  59. django_spire/contrib/utils.py +2 -0
  60. django_spire/core/static/django_spire/css/app-button.css +11 -1
  61. django_spire/core/static/django_spire/css/app-import.css +2 -0
  62. django_spire/core/static/django_spire/css/app-layout.css +15 -0
  63. django_spire/core/static/django_spire/css/app-navigation.css +24 -2
  64. django_spire/core/static/django_spire/css/app-page.css +8 -0
  65. django_spire/core/static/django_spire/css/app-side-panel.css +102 -0
  66. django_spire/core/static/django_spire/css/app-text.css +19 -1
  67. django_spire/core/static/django_spire/css/bootstrap-extension.css +128 -7
  68. django_spire/core/static/django_spire/css/bootstrap-override.css +161 -111
  69. django_spire/core/static/django_spire/css/themes/ayu/app-dark.css +0 -4
  70. django_spire/core/static/django_spire/css/themes/ayu/app-light.css +0 -4
  71. django_spire/core/static/django_spire/css/themes/catppuccin/app-dark.css +0 -4
  72. django_spire/core/static/django_spire/css/themes/catppuccin/app-light.css +0 -4
  73. django_spire/core/static/django_spire/css/themes/default/app-dark.css +0 -4
  74. django_spire/core/static/django_spire/css/themes/default/app-light.css +0 -4
  75. django_spire/core/static/django_spire/css/themes/dracula/app-dark.css +0 -4
  76. django_spire/core/static/django_spire/css/themes/dracula/app-light.css +0 -4
  77. django_spire/core/static/django_spire/css/themes/gruvbox/app-dark.css +0 -4
  78. django_spire/core/static/django_spire/css/themes/gruvbox/app-light.css +0 -4
  79. django_spire/core/static/django_spire/css/themes/material/app-dark.css +0 -4
  80. django_spire/core/static/django_spire/css/themes/material/app-light.css +0 -4
  81. django_spire/core/static/django_spire/css/themes/nord/app-dark.css +0 -4
  82. django_spire/core/static/django_spire/css/themes/nord/app-light.css +0 -4
  83. django_spire/core/static/django_spire/css/themes/oceanic-next/app-dark.css +0 -4
  84. django_spire/core/static/django_spire/css/themes/oceanic-next/app-light.css +0 -4
  85. django_spire/core/static/django_spire/css/themes/one-dark/app-dark.css +0 -4
  86. django_spire/core/static/django_spire/css/themes/one-dark/app-light.css +0 -4
  87. django_spire/core/static/django_spire/css/themes/palenight/app-dark.css +0 -4
  88. django_spire/core/static/django_spire/css/themes/palenight/app-light.css +0 -4
  89. django_spire/core/static/django_spire/css/themes/rose-pine/app-dark.css +0 -4
  90. django_spire/core/static/django_spire/css/themes/rose-pine/app-light.css +0 -4
  91. django_spire/core/static/django_spire/css/themes/synthwave/app-dark.css +0 -4
  92. django_spire/core/static/django_spire/css/themes/synthwave/app-light.css +0 -4
  93. django_spire/core/static/django_spire/css/themes/tokyo-night/app-dark.css +0 -4
  94. django_spire/core/static/django_spire/css/themes/tokyo-night/app-light.css +0 -4
  95. django_spire/core/static/django_spire/font/Poppins-Black.ttf +0 -0
  96. django_spire/core/static/django_spire/font/Poppins-BlackItalic.ttf +0 -0
  97. django_spire/core/static/django_spire/font/Poppins-Bold.ttf +0 -0
  98. django_spire/core/static/django_spire/font/Poppins-BoldItalic.ttf +0 -0
  99. django_spire/core/static/django_spire/font/Poppins-ExtraBold.ttf +0 -0
  100. django_spire/core/static/django_spire/font/Poppins-ExtraBoldItalic.ttf +0 -0
  101. django_spire/core/static/django_spire/font/Poppins-ExtraLight.ttf +0 -0
  102. django_spire/core/static/django_spire/font/Poppins-ExtraLightItalic.ttf +0 -0
  103. django_spire/core/static/django_spire/font/Poppins-Italic.ttf +0 -0
  104. django_spire/core/static/django_spire/font/Poppins-Light.ttf +0 -0
  105. django_spire/core/static/django_spire/font/Poppins-LightItalic.ttf +0 -0
  106. django_spire/core/static/django_spire/font/Poppins-Medium.ttf +0 -0
  107. django_spire/core/static/django_spire/font/Poppins-MediumItalic.ttf +0 -0
  108. django_spire/core/static/django_spire/font/Poppins-SemiBold.ttf +0 -0
  109. django_spire/core/static/django_spire/font/Poppins-SemiBoldItalic.ttf +0 -0
  110. django_spire/core/static/django_spire/font/Poppins-Thin.ttf +0 -0
  111. django_spire/core/static/django_spire/font/Poppins-ThinItalic.ttf +0 -0
  112. django_spire/core/static/django_spire/js/ui.js +12 -0
  113. django_spire/core/templates/django_spire/button/base_button.html +1 -1
  114. django_spire/core/templates/django_spire/button/primary_dark_outlined_button.html +3 -0
  115. django_spire/core/templates/django_spire/dropdown/element/dropdown_link_element.html +12 -8
  116. django_spire/core/templates/django_spire/dropdown/element/ellipsis_dropdown_modal_link_element.html +2 -1
  117. django_spire/core/templates/django_spire/dropdown/ellipsis_dropdown.html +2 -1
  118. django_spire/core/templates/django_spire/navigation/accordion/nav_accordion.html +1 -1
  119. django_spire/core/templates/django_spire/navigation/elements/nav_link.html +1 -1
  120. django_spire/core/templates/django_spire/navigation/elements/nav_title_divider.html +1 -1
  121. django_spire/core/templates/django_spire/navigation/side_navigation.html +52 -8
  122. django_spire/core/templates/django_spire/navigation/top_navigation.html +8 -2
  123. django_spire/core/templates/django_spire/page/full_page.html +218 -11
  124. django_spire/core/utils.py +26 -2
  125. django_spire/knowledge/collection/models.py +24 -0
  126. django_spire/knowledge/collection/services/transformation_service.py +2 -1
  127. django_spire/knowledge/collection/tests/test_services/test_transformation_service.py +44 -42
  128. django_spire/knowledge/collection/urls/form_urls.py +1 -0
  129. django_spire/knowledge/collection/urls/page_urls.py +1 -0
  130. django_spire/knowledge/collection/views/form_views.py +13 -2
  131. django_spire/knowledge/collection/views/page_views.py +36 -4
  132. django_spire/knowledge/entry/models.py +32 -0
  133. django_spire/knowledge/entry/services/transformation_services.py +10 -10
  134. django_spire/knowledge/entry/version/block/data/data.py +2 -1
  135. django_spire/knowledge/entry/version/block/data/heading_data.py +2 -2
  136. django_spire/knowledge/entry/version/block/data/list/data.py +3 -4
  137. django_spire/knowledge/entry/version/block/data/maps.py +3 -5
  138. django_spire/knowledge/entry/version/block/data/text_data.py +2 -2
  139. django_spire/knowledge/entry/version/block/models.py +10 -7
  140. django_spire/knowledge/entry/version/block/services/factory_service.py +11 -10
  141. django_spire/knowledge/entry/version/block/tests/factories.py +6 -5
  142. django_spire/knowledge/entry/version/converters/docx_converter.py +2 -4
  143. django_spire/knowledge/entry/version/intelligence/bots/markdown_format_llm_bot.py +16 -12
  144. django_spire/knowledge/entry/version/seeding/seeder.py +3 -3
  145. django_spire/knowledge/entry/version/services/processor_service.py +36 -10
  146. django_spire/knowledge/entry/version/tests/test_converters/test_docx_converter.py +1 -1
  147. django_spire/knowledge/entry/version/tests/test_urls/test_page_urls.py +1 -1
  148. django_spire/knowledge/entry/version/urls/page_urls.py +1 -1
  149. django_spire/knowledge/entry/version/views/json_views.py +5 -3
  150. django_spire/knowledge/entry/version/views/page_views.py +11 -12
  151. django_spire/knowledge/entry/version/views/redirect_views.py +1 -1
  152. django_spire/knowledge/entry/views/form_views.py +1 -1
  153. django_spire/knowledge/intelligence/bots/entry_search_llm_bot.py +33 -11
  154. django_spire/knowledge/intelligence/decoders/__init__.py +0 -0
  155. django_spire/knowledge/intelligence/{maps/collection_map.py → decoders/collection_decoder.py} +5 -5
  156. django_spire/knowledge/intelligence/{maps/entry_map.py → decoders/entry_decoder.py} +3 -3
  157. django_spire/knowledge/intelligence/intel/collection_intel.py +1 -0
  158. django_spire/knowledge/intelligence/intel/entry_intel.py +5 -2
  159. django_spire/knowledge/intelligence/intel/message_intel.py +2 -0
  160. django_spire/knowledge/intelligence/workflows/knowledge_workflow.py +43 -51
  161. django_spire/knowledge/migrations/0007_alter_collection_options.py +17 -0
  162. django_spire/knowledge/static/django_spire/knowledge/entry/version/js/editor.js +24 -5
  163. django_spire/knowledge/templates/django_spire/knowledge/collection/card/top_level_list_card.html +21 -0
  164. django_spire/knowledge/templates/django_spire/knowledge/collection/component/x_collection_navigation.html +15 -6
  165. django_spire/knowledge/templates/django_spire/knowledge/collection/element/ellipsis_dropdown.html +22 -0
  166. django_spire/knowledge/templates/django_spire/knowledge/collection/form/form.html +21 -9
  167. django_spire/knowledge/templates/django_spire/knowledge/collection/item/collection_item.html +19 -0
  168. django_spire/knowledge/templates/django_spire/knowledge/collection/page/display_page.html +49 -0
  169. django_spire/knowledge/templates/django_spire/knowledge/collection/page/form_page.html +1 -1
  170. django_spire/knowledge/templates/django_spire/knowledge/container/container.html +33 -0
  171. django_spire/knowledge/templates/django_spire/knowledge/entry/file/page/list_page.html +1 -1
  172. django_spire/knowledge/templates/django_spire/knowledge/entry/item/list_item.html +2 -2
  173. django_spire/knowledge/templates/django_spire/knowledge/entry/page/form_page.html +1 -1
  174. django_spire/knowledge/templates/django_spire/knowledge/entry/page/import_form_page.html +1 -1
  175. django_spire/knowledge/templates/django_spire/knowledge/entry/version/container/detail_container.html +51 -45
  176. django_spire/knowledge/templates/django_spire/knowledge/entry/version/page/editor_page.html +54 -0
  177. django_spire/knowledge/templates/django_spire/knowledge/entry/version/page/form_page.html +1 -1
  178. django_spire/knowledge/templates/django_spire/knowledge/message/knowledge_message_intel.html +18 -1
  179. django_spire/knowledge/templates/django_spire/knowledge/page/full_page.html +37 -0
  180. django_spire/knowledge/templates/django_spire/knowledge/page/home_page.html +2 -2
  181. django_spire/knowledge/templates/django_spire/knowledge/sub_navigation/item/collection_sub_navigation_item.html +29 -0
  182. django_spire/knowledge/templates/django_spire/knowledge/sub_navigation/item/entry_sub_navigation_item.html +20 -0
  183. django_spire/knowledge/templates/django_spire/knowledge/{navigation/content/navigation_content.html → sub_navigation/widget/collection_entry_sub_navigation_widget.html} +42 -19
  184. django_spire/knowledge/views/page_views.py +4 -4
  185. django_spire/settings.py +3 -3
  186. django_spire/theme/templates/django_spire/theme/card/badges_preview_card.html +0 -1
  187. django_spire/theme/templates/django_spire/theme/card/base_preview_card.html +1 -0
  188. django_spire/theme/templates/django_spire/theme/card/typography_preview_card.html +1 -1
  189. django_spire/theme/templates/django_spire/theme/example/form/example_form.html +2 -0
  190. django_spire/theme/templates/django_spire/theme/example/form/example_form_card.html +5 -0
  191. django_spire/theme/templates/django_spire/theme/page/badges_page.html +7 -9
  192. django_spire/theme/templates/django_spire/theme/page/borders_page.html +6 -9
  193. django_spire/theme/templates/django_spire/theme/page/buttons_page.html +6 -9
  194. django_spire/theme/templates/django_spire/theme/page/colors_page.html +6 -6
  195. django_spire/theme/templates/django_spire/theme/page/dashboard_page.html +57 -0
  196. django_spire/theme/templates/django_spire/theme/page/django_glue_page.html +7 -9
  197. django_spire/theme/templates/django_spire/theme/page/theme_page.html +24 -0
  198. django_spire/theme/templates/django_spire/theme/page/typography_page.html +6 -9
  199. django_spire/theme/templates/django_spire/theme/section/badge_section_card.html +5 -0
  200. django_spire/theme/templates/django_spire/theme/section/border_section_card.html +5 -0
  201. django_spire/theme/templates/django_spire/theme/section/button_section.html +1 -0
  202. django_spire/theme/templates/django_spire/theme/section/button_section_card.html +5 -0
  203. django_spire/theme/templates/django_spire/theme/section/color_section.html +10 -10
  204. django_spire/theme/templates/django_spire/theme/section/color_section_card.html +5 -0
  205. django_spire/theme/templates/django_spire/theme/section/typography_section.html +41 -1
  206. django_spire/theme/templates/django_spire/theme/section/typography_section_card.html +5 -0
  207. {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/METADATA +3 -3
  208. {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/RECORD +217 -178
  209. django_spire/ai/chat/intelligence/bots/chat_bot.py +0 -8
  210. django_spire/ai/chat/intelligence/maps/intent_llm_map.py +0 -10
  211. django_spire/ai/chat/templates/django_spire/ai/chat/page/home_page.html +0 -9
  212. django_spire/ai/chat/templates/django_spire/ai/chat/widget/chat_widget.html +0 -64
  213. django_spire/ai/chat/templates/django_spire/ai/chat/widget/search_chat_results_widget.html +0 -25
  214. django_spire/ai/chat/templates/django_spire/ai/chat/widget/search_chat_widget.html +0 -39
  215. django_spire/ai/chat/templates/django_spire/ai/chat/widget/select_chat_widget.html +0 -24
  216. django_spire/ai/chat/tools.py +0 -57
  217. django_spire/ai/sms/tools.py +0 -57
  218. django_spire/core/static/django_spire/font/Karla-Bold.ttf +0 -0
  219. django_spire/core/static/django_spire/font/Merriweather.ttf +0 -0
  220. django_spire/knowledge/context_processors.py +0 -18
  221. django_spire/knowledge/templates/django_spire/knowledge/entry/version/page/detail_page.html +0 -25
  222. django_spire/knowledge/templates/django_spire/knowledge/navigation/card/navigation_card.html +0 -9
  223. django_spire/knowledge/templates/django_spire/knowledge/navigation/item/collection/collection_item.html +0 -29
  224. django_spire/knowledge/templates/django_spire/knowledge/navigation/item/entry/entry_item.html +0 -18
  225. django_spire/knowledge/templates/django_spire/knowledge/navigation/page/full_page.html +0 -90
  226. /django_spire/ai/chat/intelligence/{bots → decoders}/__init__.py +0 -0
  227. /django_spire/ai/chat/{intelligence/maps → urls/template}/__init__.py +0 -0
  228. /django_spire/{knowledge/intelligence/maps → ai/chat/views/template}/__init__.py +0 -0
  229. /django_spire/knowledge/entry/version/{constants.py → consts.py} +0 -0
  230. /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
  231. /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
  232. {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/WHEEL +0 -0
  233. {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/licenses/LICENSE.md +0 -0
  234. {django_spire-0.18.2.dist-info → django_spire-0.19.0.dist-info}/top_level.txt +0 -0
@@ -1,56 +1,48 @@
1
1
  from __future__ import annotations
2
2
 
3
- from django_spire.knowledge.intelligence.bots.entry_search_llm_bot import EntrySearchLlmBot
4
- from django_spire.knowledge.intelligence.intel.collection_intel import CollectionIntel
5
- from django_spire.knowledge.intelligence.intel.entry_intel import EntriesIntel, EntryIntel
3
+ from typing import TYPE_CHECKING
4
+
5
+ from django.core.handlers.wsgi import WSGIRequest
6
+ from django_spire.knowledge.intelligence.bots.entry_search_llm_bot import EntrySearchBot
7
+ from django_spire.knowledge.intelligence.intel.entry_intel import EntriesIntel
6
8
  from django_spire.knowledge.intelligence.intel.message_intel import KnowledgeMessageIntel
7
- from django_spire.knowledge.intelligence.maps.collection_map import get_collection_map_class
8
- from django_spire.knowledge.intelligence.maps.entry_map import get_entry_map_class
9
-
10
-
11
- class KnowledgeWorkflow:
12
- @classmethod
13
- def process(cls, user_input: str) -> KnowledgeMessageIntel:
14
- CollectionMap = get_collection_map_class()
15
- collections = CollectionMap().process(user_input).values
16
-
17
- if collections[0] is None:
18
- return KnowledgeMessageIntel(
19
- body=(
20
- 'There was no knowledge related to your request. Please reword it '
21
- 'and try again.'
22
- )
23
- )
24
-
25
- entries = []
26
- for collection in collections:
27
- if collection.entry_count > 0:
28
- EntryMap = get_entry_map_class(collection=collection)
29
- entries.extend(EntryMap().process(user_input).values)
30
-
31
- entries = [entry for entry in entries if entry is not None]
32
-
33
- if not entries:
34
- return KnowledgeMessageIntel(
35
- body=(
36
- 'There was no knowledge related to your request. Please reword it '
37
- 'and try again.'
38
- )
39
- )
40
-
41
- entry_search_bot = EntrySearchLlmBot()
42
-
43
- entries_intel = EntriesIntel(
44
- entry_intel_list=[
45
- EntryIntel(
46
- body=entry_search_bot.process(
47
- user_input=user_input,
48
- entry=entry
49
- ),
50
- collection_intel=CollectionIntel(name=entry.collection.name)
51
- )
52
- for entry in entries
53
- ]
9
+ from django_spire.knowledge.intelligence.decoders.collection_decoder import get_collection_decoder
10
+ from django_spire.knowledge.intelligence.decoders.entry_decoder import get_entry_decoder
11
+
12
+ if TYPE_CHECKING:
13
+ from django.core.handlers.wsgi import WSGIRequest
14
+ from dandy.llm.request.message import MessageHistory
15
+
16
+
17
+ def knowledge_search_workflow(
18
+ request: WSGIRequest,
19
+ user_input: str,
20
+ message_history: MessageHistory,
21
+ ) -> KnowledgeMessageIntel | None:
22
+ collection_decoder = get_collection_decoder()
23
+ collections = collection_decoder.process(user_input).values
24
+
25
+ if collections[0] is None:
26
+ return None
27
+
28
+ entries = []
29
+
30
+ for collection in collections:
31
+ if collection.entry_count > 0:
32
+ entry_decoder = get_entry_decoder(collection=collection)
33
+
34
+ entries.extend(entry_decoder.process(user_input).values)
35
+
36
+ entries = [entry for entry in entries if entry is not None]
37
+
38
+ if not entries:
39
+ return None
40
+
41
+ entries_intel = EntriesIntel(entry_intel_list=[])
42
+
43
+ for entry in entries:
44
+ entries_intel.append(
45
+ EntrySearchBot().process(user_input=user_input, entry=entry)
54
46
  )
55
47
 
56
- return KnowledgeMessageIntel(body=f'Entries: {entries_intel}')
48
+ return KnowledgeMessageIntel(body=f'Entries: {entries_intel}', entries_intel=entries_intel)
@@ -0,0 +1,17 @@
1
+ # Generated by Django 5.2.7 on 2025-11-07 23:13
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('django_spire_knowledge', '0006_alter_entryversionblock_type'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterModelOptions(
14
+ name='collection',
15
+ options={'ordering': ['name'], 'permissions': [('can_access_all_collections', 'Can Access All Collections'), ('can_change_collection_groups', 'Can Change Collection Groups')], 'verbose_name': 'Collection', 'verbose_name_plural': 'Collections'},
16
+ ),
17
+ ]
@@ -33,10 +33,11 @@ function create_editorjs_instance({holder_id, update_url, initial_editor_blocks}
33
33
  const raw_editor_blocks = await api.saver.save()
34
34
 
35
35
  const parsed_editor_blocks = raw_editor_blocks.blocks.map((block, i) => ({
36
- block_order: i,
37
- block_data: block.data,
38
- block_type: block.type,
39
- block_tunes: block?.tunes ?? {},
36
+ id: block.id,
37
+ order: i,
38
+ data: block.data,
39
+ type: block.type,
40
+ tunes: block?.tunes ?? {},
40
41
  }))
41
42
 
42
43
  try {
@@ -68,6 +69,24 @@ function create_editorjs_instance({holder_id, update_url, initial_editor_blocks}
68
69
  if (should_init_editor_in_edit_mode()) {
69
70
  focus_editor()
70
71
  }
72
+
73
+ const block_id = new URLSearchParams(window.location.search).get('block_id')
74
+
75
+ if (block_id) {
76
+ setTimeout(() => {
77
+ const element = document.querySelector(`[data-id="${block_id}"]`)
78
+ console.log('element', element)
79
+ if (element) {
80
+ element.scrollIntoView({behavior: 'smooth', block: 'center'})
81
+ element.style.transition = 'background-color 1s ease'
82
+ element.classList.add('bg-app-accent-soft', 'mx-3', 'rounded-3')
83
+ setTimeout(() => {
84
+ element.classList.remove('bg-app-accent-soft')
85
+ }, 4000)
86
+ }
87
+ }, 100)
88
+ }
89
+
71
90
  }
72
91
  }
73
92
  catch (e) {
@@ -84,4 +103,4 @@ function focus_editor() {
84
103
 
85
104
  function should_init_editor_in_edit_mode() {
86
105
  return new URLSearchParams(window.location.search).get('view_mode') === 'edit'
87
- }
106
+ }
@@ -0,0 +1,21 @@
1
+ {% extends 'django_spire/card/title_card.html' %}
2
+
3
+ {% block card_title %}
4
+ Knowledge Collections
5
+ {% endblock %}
6
+
7
+ {% block card_button %}
8
+ {% if AuthController.knowledge.can_add %}
9
+ {% url 'django_spire:knowledge:collection:form:create' as create_url %}
10
+ {% include 'django_spire/button/primary_button.html' with button_text='Add' button_href=create_url button_url_params='?top_level=True' button_icon="bi bi-plus" %}
11
+ {% endif %}
12
+ {% endblock %}
13
+
14
+ {% block card_title_content %}
15
+ {% for collection in collections %}
16
+ {% include 'django_spire/knowledge/collection/item/collection_item.html' %}
17
+ {% empty %}
18
+ No Items Found
19
+ {% endfor %}
20
+ {% endblock %}
21
+
@@ -13,10 +13,19 @@
13
13
  @dragend="toggle_dragging(false)"
14
14
  {% endif %}
15
15
  :id="collection.name"
16
- class="my-1 ms-4 collection"
16
+ :class="{'ms-4': collection.parent.id !== -1}"
17
+ class="mb-1 collection"
17
18
  >
18
- {% include 'django_spire/knowledge/navigation/item/collection/collection_item.html' %}
19
- <div x-show="collection.show_details" class="my-1">
19
+ <div x-data="{
20
+ init() {
21
+ console.log(collection)
22
+ }
23
+ }">
24
+
25
+ </div>
26
+ {% include 'django_spire/knowledge/sub_navigation/item/collection_sub_navigation_item.html' %}
27
+
28
+ <div x-show="is_expanded(collection.id)" class="my-1">
20
29
  <x-collection-navigation :data="{items: collection.children, id: collection.id}"></x-collection-navigation>
21
30
  <div class="ms-4">
22
31
  <div
@@ -27,15 +36,15 @@
27
36
  >
28
37
  <template x-for="entry in collection.entries" :key="entry.version_id">
29
38
  <div
30
- class="entry"
39
+ class="mb-1 entry"
31
40
  {% if AuthController.knowledge.can_change %}
32
- x-sort:item="collection"
41
+ x-sort:item="entry"
33
42
  @dragstart="toggle_dragging(true)"
34
43
  @dragend="toggle_dragging(false)"
35
44
  {% endif %}
36
45
  :id="entry.name"
37
46
  >
38
- {% include 'django_spire/knowledge/navigation/item/entry/entry_item.html' %}
47
+ {% include 'django_spire/knowledge/sub_navigation/item/entry_sub_navigation_item.html' %}
39
48
  </div>
40
49
  </template>
41
50
  </div>
@@ -0,0 +1,22 @@
1
+ {% extends 'django_spire/dropdown/ellipsis_dropdown.html' %}
2
+
3
+ {% block dropdown_content %}
4
+ {% if AuthController.knowledge.can_change %}
5
+ {% url 'django_spire:knowledge:collection:form:update' pk=collection.pk as edit_url %}
6
+ {% include 'django_spire/dropdown/element/dropdown_link_element.html' with link_url=edit_url link_icon='bi bi-pencil' link_text='Edit Collection' %}
7
+ {% endif %}
8
+
9
+ {% if AuthController.knowledge.can_add %}
10
+ {% url 'django_spire:knowledge:entry:form:create' collection_pk=collection.pk as create_entry_url %}
11
+ {% include 'django_spire/dropdown/element/dropdown_link_element.html' with link_url=create_entry_url link_icon='bi bi-plus' link_text='Add Entry' %}
12
+
13
+ {% url 'django_spire:knowledge:entry:form:import' collection_pk=collection.pk as import_entry_url %}
14
+ {% include 'django_spire/dropdown/element/dropdown_link_element.html' with link_url=import_entry_url link_icon='bi bi-upload' link_text='Import Entry' %}
15
+ {% endif %}
16
+
17
+ {% if AuthController.knowledge.can_delete %}
18
+ {% url 'django_spire:knowledge:collection:page:delete' pk=collection.pk as delete_url %}
19
+ {% include 'django_spire/dropdown/element/dropdown_link_element.html' with link_url=delete_url link_icon='bi bi-trash3' link_text='Delete Collection' link_css='text-app-danger' %}
20
+ {% endif %}
21
+ {% endblock %}
22
+
@@ -1,8 +1,8 @@
1
1
  <form
2
- class="row"
3
- method="post"
4
- action="{% url 'django_spire:knowledge:collection:form:update' pk=collection.pk|default:0 %}"
5
- x-data="{
2
+ class="row"
3
+ method="post"
4
+ action="{% url 'django_spire:knowledge:collection:form:update' pk=collection.pk|default:0 %}"
5
+ x-data="{
6
6
  collection: new ModelObjectGlue('collection'),
7
7
  collection_query_set: new QuerySetGlue('collections'),
8
8
  groups: new GlueCharField('groups'),
@@ -11,6 +11,11 @@
11
11
  await this.collection.get()
12
12
  this.collection.glue_fields.parent.choices = await this.collection_query_set.to_choices()
13
13
  this.collection.glue_fields.parent.label = 'Parent Collection'
14
+ console.log(this.collection.parent)
15
+
16
+ if (!this.collection.parent) {
17
+ this.collection.parent = {{ collection_parent_pk|default:'null' }}
18
+ }
14
19
 
15
20
  this.groups.choices = await this.group_query_set.to_choices()
16
21
  this.groups.value = JSON.parse('{{ group_ids }}')
@@ -18,21 +23,28 @@
18
23
  }"
19
24
  >
20
25
  {% csrf_token %}
26
+
21
27
  <div class="col-12">
22
28
  {% include 'django_glue/form/field/char_field.html' with glue_model_field='collection.name' %}
23
29
  </div>
30
+
24
31
  <div class="col-12 mt-2">
25
32
  {% include 'django_glue/form/field/char_field.html' with glue_model_field='collection.description' %}
26
33
  </div>
27
- <div class="col-12 mt-2">
28
- {% include 'django_glue/form/field/search_and_select_field.html' with glue_model_field='collection.parent' %}
29
- </div>
34
+
30
35
  {% if AuthController.knowledge.can_change_collection_groups %}
31
- <div class="col-12 mt-2">
36
+ <div class="col-12 col-lg mt-2">
32
37
  {% include 'django_glue/form/field/multi_select_field.html' with glue_field='groups' %}
33
38
  </div>
34
39
  {% endif %}
35
- <div class="col-12 mt-2">
40
+
41
+ {% if request.GET.top_level != 'True' %}
42
+ <div class="col-12 col-lg mt-2">
43
+ {% include 'django_glue/form/field/search_and_select_field.html' with glue_model_field='collection.parent' %}
44
+ </div>
45
+ {% endif %}
46
+
47
+ <div class="col-12 mt-3">
36
48
  {% include 'django_spire/contrib/form/button/form_submit_button.html' %}
37
49
  </div>
38
50
  </form>
@@ -0,0 +1,19 @@
1
+ {% extends 'django_spire/item/item.html' %}
2
+
3
+ {% block item_title %}
4
+ <a href="{% url 'django_spire:knowledge:collection:page:top_level' pk=collection.id %}">
5
+ {{ collection.name }}
6
+ </a>
7
+ {% endblock %}
8
+
9
+ {% block item_row_content %}
10
+ <div class="row">
11
+ <div class="col fs-7 text-muted pt-2">
12
+ {{ collection.description }}
13
+ </div>
14
+ </div>
15
+ {% endblock %}
16
+
17
+ {% block item_button %}
18
+ {% include 'django_spire/knowledge/collection/element/ellipsis_dropdown.html' %}
19
+ {% endblock %}
@@ -0,0 +1,49 @@
1
+ {% extends 'django_spire/knowledge/page/full_page.html' %}
2
+
3
+ {% block full_page_sub_navigation_title %}
4
+ {{ collection.name_short }}
5
+ {% endblock %}
6
+
7
+ {% block full_page_sub_navigation_buttons %}
8
+ {% if AuthController.knowledge.can_add %}
9
+ {% url 'django_spire:knowledge:collection:form:create_with_parent' parent_pk=collection.id as create_url %}
10
+ {% include 'django_spire/button/primary_button.html' with button_text='Add' button_href=create_url button_icon="bi bi-plus" %}
11
+ {% endif %}
12
+ {% endblock %}
13
+
14
+ {% block full_page_sub_navigation %}
15
+ {% include 'django_spire/knowledge/sub_navigation/widget/collection_entry_sub_navigation_widget.html' with current_collection_id=entry.collection.id current_version_id=current_version.id %}
16
+ {% endblock %}
17
+
18
+ {% block knowledge_full_page_content %}
19
+ <div class="row">
20
+ <div class="col-12 col-lg-8 mx-auto pb-4 h4 text-app-primary">
21
+ {{ collection.name }}
22
+ </div>
23
+ </div>
24
+ <div class="row">
25
+ <div class="col-12 col-lg-8 mx-auto pb-4">
26
+ Description:<br>{{ collection.description }}
27
+ </div>
28
+ </div>
29
+ <div class="row">
30
+ <div class="col-12 col-lg-8 mx-auto pb-4">
31
+ Sub Collections:<br>{{ collection.children.count }}
32
+ </div>
33
+ </div>
34
+ <div class="row">
35
+ <div class="col-12 col-lg-8 mx-auto pb-4">
36
+ Entries:<br>{{ collection.entries.count }}
37
+ </div>
38
+ </div>
39
+ <div class="row">
40
+ <div class="col-12 col-lg-8 mx-auto pb-4">
41
+ Popular Collections & Entries ETC
42
+ </div>
43
+ </div>
44
+ <div class="row">
45
+ <div class="col-12 col-lg-8 mx-auto pb-4">
46
+ Last Edits ETC
47
+ </div>
48
+ </div>
49
+ {% endblock %}
@@ -1,4 +1,4 @@
1
- {% extends 'django_spire/knowledge/navigation/page/full_page.html' %}
1
+ {% extends 'django_spire/knowledge/page/full_page.html' %}
2
2
 
3
3
  {% block knowledge_full_page_content %}
4
4
  <div class="row">
@@ -0,0 +1,33 @@
1
+ <div class="row {% block container_outer_class %}{% endblock %}">
2
+ <div class="col-12">
3
+ <div class="my-4 pb-4 px-md-3">
4
+ <div class="align-items-center d-flex justify-content-between mx-auto" style="max-width: 1200px;">
5
+ <div class="flex-grow-1 text-center">
6
+ <h1 class="fs-2 fw-bold mb-2 text-app-primary">
7
+ {% block container_title %}
8
+ {% endblock %}
9
+ </h1>
10
+ <div class="fs-6 text-alt-color">
11
+ {% block container_subtitle %}
12
+ {% endblock %}
13
+ </div>
14
+ </div>
15
+
16
+ <div class="flex-shrink-0 ms-3">
17
+ {% block container_button %}
18
+ {% endblock %}
19
+ </div>
20
+ </div>
21
+ </div>
22
+
23
+ {% block container_filter_section %}
24
+ {% endblock %}
25
+
26
+ <div class="row {% block container_class %}{% endblock %}">
27
+ <div class="col-12 {% block container_content_class %}{% endblock %}">
28
+ {% block container_content %}
29
+ {% endblock %}
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
@@ -1,4 +1,4 @@
1
- {% extends 'django_spire/knowledge/navigation/page/full_page.html' %}
1
+ {% extends 'django_spire/knowledge/navigation/page/../../../page/full_page.html' %}
2
2
 
3
3
  {% block full_page_content %}
4
4
  <div class="row">
@@ -4,7 +4,7 @@
4
4
  <div class="row m-0">
5
5
  {% include 'django_spire/element/grabber_element.html' with grabber_class='col-auto align-self-center' %}
6
6
  <div class="col">
7
- {% url 'django_spire:knowledge:entry:version:page:detail' pk=entry.current_version_id as entry_detail_url %}
7
+ {% url 'django_spire:knowledge:entry:version:page:editor' pk=entry.current_version_id as entry_detail_url %}
8
8
  {% include 'django_spire/element/attribute_element.html' with attribute_value=entry.name attribute_href=entry_detail_url %}
9
9
  </div>
10
10
  </div>
@@ -29,7 +29,7 @@
29
29
 
30
30
  {% block item_button %}
31
31
  {% if AuthController.knowledge.can_view %}
32
- {% url 'django_spire:knowledge:entry:version:page:detail' pk=entry.current_version_id as entry_detail_url %}
32
+ {% url 'django_spire:knowledge:entry:version:page:editor' pk=entry.current_version_id as entry_detail_url %}
33
33
  {% endif %}
34
34
  {% if AuthController.knowledge.can_change %}
35
35
  {% url 'django_spire:knowledge:entry:form:update' pk=entry.pk collection_pk=collection.pk as entry_edit_url %}
@@ -1,4 +1,4 @@
1
- {% extends 'django_spire/knowledge/navigation/page/full_page.html' %}
1
+ {% extends 'django_spire/knowledge/navigation/page/../../page/full_page.html' %}
2
2
 
3
3
  {% block knowledge_full_page_content %}
4
4
  <div class="row">
@@ -1,4 +1,4 @@
1
- {% extends 'django_spire/knowledge/navigation/page/full_page.html' %}
1
+ {% extends 'django_spire/knowledge/navigation/page/../../page/full_page.html' %}
2
2
 
3
3
  {% block knowledge_full_page_content %}
4
4
  <div class="row">
@@ -1,71 +1,77 @@
1
- {% extends 'django_spire/container/container.html' %}
1
+ {% extends 'django_spire/knowledge/container/container.html' %}
2
2
 
3
3
  {% block container_title %}
4
4
  {{ entry.name }}
5
5
  {% endblock %}
6
6
 
7
- {% block container_button %}
8
- <div class="container">
9
- <div class="row align-items-center">
10
- {% if AuthController.knowledge.can_change %}
11
- <div
12
- class="col"
13
- x-data="{
14
- editor_is_readonly: !should_init_editor_in_edit_mode(),
15
- toggle_editor_readonly() {
16
- KNOWLEDGE_ENTRY_VERSION_EDITOR?.readOnly?.toggle()
17
- this.editor_is_readonly = KNOWLEDGE_ENTRY_VERSION_EDITOR?.readOnly?.isEnabled
7
+ {% block container_subtitle %}
8
+ <div class="row">
9
+ <div class="col text-end">
10
+ {% if not entry.current_version.is_published and AuthController.knowledge.can_change %}
11
+ {% include 'django_spire/knowledge/entry/modal/publish_confirm_modal.html' %}
12
+ {% else %}
13
+ {% include 'django_spire/knowledge/entry/badge/entry_status_badge.html' with status=entry.current_version.status %}
14
+ {% endif %}
15
+ </div>
16
+ {% if AuthController.knowledge.can_change %}
17
+ <div class="col text-start"
18
+ x-data="{
19
+ editor_is_readonly: !should_init_editor_in_edit_mode(),
20
+ toggle_editor_readonly() {
21
+ KNOWLEDGE_ENTRY_VERSION_EDITOR?.readOnly?.toggle()
22
+ this.editor_is_readonly = KNOWLEDGE_ENTRY_VERSION_EDITOR?.readOnly?.isEnabled
18
23
 
19
- const view_mode = this.editor_is_readonly ? 'readonly' : 'edit'
24
+ let view_mode = this.editor_is_readonly ? 'readonly' : 'edit'
20
25
 
21
- const url = new URL(window.location)
22
- url.searchParams.set('view_mode', view_mode)
23
- history.pushState(null, '', url);
24
- }
25
- }"
26
- >
27
- <div class="btn shadow-sm btn-md btn-app-primary"
28
- @click="
29
- toggle_editor_readonly();
30
- ">
31
- <span x-text="editor_is_readonly ? 'Edit' : 'Save'"></span>
32
- </div>
33
- </div>
34
- {% endif %}
35
- <div class="col">
36
- {% if not entry.current_version.is_published and AuthController.knowledge.can_change %}
37
- {% include 'django_spire/knowledge/entry/modal/publish_confirm_modal.html' %}
38
- {% else %}
39
- {% include 'django_spire/knowledge/entry/badge/entry_status_badge.html' with status=entry.current_version.status %}
40
- {% endif %}
26
+ let url = new URL(window.location)
27
+ url.searchParams.set('view_mode', view_mode)
28
+ history.pushState(null, '', url);
29
+ }
30
+ }"
31
+ >
32
+ <div
33
+ @click="toggle_editor_readonly();"
34
+ class="btn btn-app-primary btn-sm shadow-sm"
35
+ >
36
+ <i :class="editor_is_readonly ? 'bi bi-pencil' : 'bi bi-check-lg'" class="me-1"></i>
37
+ <span x-text="editor_is_readonly ? 'Edit' : 'Save'"></span>
41
38
  </div>
42
39
  </div>
40
+ {% endif %}
43
41
  </div>
44
42
  {% endblock %}
45
43
 
44
+
46
45
  {% block container_content %}
47
46
  <div class="container">
48
47
  <div class="row px-3">
49
- <script>
50
- // Define editor instance outside of alpine js scope to avoid potential issues caused by reactivity
51
- // and to allow above button to access
52
- let KNOWLEDGE_ENTRY_VERSION_EDITOR;
53
- </script>
48
+ <div class="col">
49
+ <script>
50
+ // Define editor instance outside of alpine js scope to avoid potential issues caused by reactivity
51
+ // and to allow above button to access
52
+ let KNOWLEDGE_ENTRY_VERSION_EDITOR;
53
+ </script>
54
54
 
55
- {# The EditorJS will be attached to this div #}
56
- <div
57
- x-data="{
55
+ {# The EditorJS will be attached to this div #}
56
+ <div
57
+ :id="editor_element_id"
58
+ x-data="{
58
59
  editor_element_id: 'knowledge-entry-version-editor',
59
60
  init() {
61
+ console.log('Editor blocks:', {{ version_blocks }})
60
62
  KNOWLEDGE_ENTRY_VERSION_EDITOR = create_editorjs_instance({
61
63
  holder_id: this.editor_element_id,
62
- update_url: '{% url "django_spire:knowledge:entry:version:json:update_blocks" pk=entry.id %}',
63
- initial_editor_blocks: {{ version_blocks }}
64
+ initial_editor_blocks: {{ version_blocks }},
65
+ update_url: '{% url "django_spire:knowledge:entry:version:json:update_blocks" pk=entry.id %}'
64
66
  })
67
+ console.log('Editor initialized:', KNOWLEDGE_ENTRY_VERSION_EDITOR)
68
+ console.log(KNOWLEDGE_ENTRY_VERSION_EDITOR)
69
+
65
70
  }
71
+
66
72
  }"
67
- :id="editor_element_id"
68
- >
73
+ >
74
+ </div>
69
75
  </div>
70
76
  </div>
71
77
  </div>
@@ -0,0 +1,54 @@
1
+ {% extends 'django_spire/knowledge/page/full_page.html' %}
2
+
3
+ {% load static %}
4
+
5
+ {% block base_body_additional_top_js %}
6
+ {{ block.super }}
7
+
8
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@2.31.0/dist/editorjs.umd.min.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph@2.11.7/dist/paragraph.umd.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/list@2.0.8/dist/editorjs-list.umd.min.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/header@2.8.8/dist/header.umd.min.js"></script>
12
+ {% endblock %}
13
+
14
+ {% block full_page_sub_navigation %}
15
+ {% include 'django_spire/knowledge/sub_navigation/widget/collection_entry_sub_navigation_widget.html' with current_collection_id=entry.collection.id current_version_id=current_version.id %}
16
+ {% endblock %}
17
+
18
+ {% block full_page_info_navigation %}
19
+ <div>
20
+ <div class="mb-3">
21
+ {% include 'django_spire/element/attribute_element.html' with attribute_title='Author' attribute_value=entry.current_version.author.get_full_name %}
22
+ </div>
23
+
24
+ <div class="mb-3">
25
+ {% include 'django_spire/element/attribute_element.html' with attribute_title='Status' %}
26
+ {% include 'django_spire/knowledge/entry/badge/entry_status_badge.html' with status=entry.current_version.status %}
27
+ </div>
28
+
29
+ {% if entry.current_version.published_datetime %}
30
+ <div class="mb-3">
31
+ {% include 'django_spire/element/attribute_element.html' with attribute_title='Published' attribute_value=entry.current_version.published_datetime %}
32
+ </div>
33
+ {% endif %}
34
+
35
+ <div class="mb-3">
36
+ {% include 'django_spire/element/attribute_element.html' with attribute_title='Last Edit' attribute_value=entry.current_version.last_edit_datetime %}
37
+ </div>
38
+ </div>
39
+ {% endblock %}
40
+
41
+ {% block knowledge_full_page_content %}
42
+ <div class="row justify-content-center ps-3">
43
+ <div class="col-12">
44
+ {% include 'django_spire/knowledge/entry/version/container/detail_container.html' %}
45
+ </div>
46
+ </div>
47
+ {% endblock %}
48
+
49
+ {% block base_body_additional_bottom_js %}
50
+ {{ block.super }}
51
+
52
+ <script src="{% static 'django_spire/knowledge/entry/version/js/null_paragraph.js' %}?v={{ DJANGO_SPIRE_VERSION }}" type="application/javascript"></script>
53
+ <script src="{% static 'django_spire/knowledge/entry/version/js/editor.js' %}?v={{ DJANGO_SPIRE_VERSION }}" type="application/javascript"></script>
54
+ {% endblock %}