django-cfg 1.3.11__py3-none-any.whl → 1.4.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 (439) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/inlines.py +11 -5
  3. django_cfg/apps/accounts/admin/user_admin.py +39 -16
  4. django_cfg/apps/accounts/serializers/profile.py +1 -1
  5. django_cfg/apps/accounts/services/otp_service.py +18 -11
  6. django_cfg/apps/accounts/signals.py +15 -24
  7. django_cfg/apps/accounts/utils/notifications.py +217 -358
  8. django_cfg/apps/accounts/views/otp.py +2 -2
  9. django_cfg/apps/accounts/views/webhook.py +1 -1
  10. django_cfg/apps/agents/core/django_agent.py +1 -1
  11. django_cfg/apps/api/commands/views.py +66 -83
  12. django_cfg/apps/api/health/drf_views.py +269 -0
  13. django_cfg/apps/api/health/serializers.py +45 -0
  14. django_cfg/apps/api/health/urls.py +6 -1
  15. django_cfg/apps/knowbase/admin/actions/__init__.py +13 -0
  16. django_cfg/apps/knowbase/admin/actions/visibility_actions.py +56 -0
  17. django_cfg/apps/knowbase/admin/document_admin.py +136 -270
  18. django_cfg/apps/knowbase/admin/helpers/__init__.py +17 -0
  19. django_cfg/apps/knowbase/admin/helpers/configs.py +72 -0
  20. django_cfg/apps/knowbase/admin/helpers/display_helpers.py +156 -0
  21. django_cfg/apps/knowbase/admin/helpers/statistics.py +108 -0
  22. django_cfg/apps/knowbase/config/constance_fields.py +1 -1
  23. django_cfg/apps/knowbase/config/settings.py +2 -2
  24. django_cfg/apps/knowbase/mixins/__init__.py +19 -2
  25. django_cfg/apps/knowbase/mixins/config/__init__.py +14 -0
  26. django_cfg/apps/knowbase/mixins/config/defaults.py +75 -0
  27. django_cfg/apps/knowbase/mixins/config/meta_config.py +120 -0
  28. django_cfg/apps/knowbase/mixins/creator.py +10 -10
  29. django_cfg/apps/knowbase/mixins/external_data_mixin.py +105 -403
  30. django_cfg/apps/knowbase/mixins/generators/__init__.py +16 -0
  31. django_cfg/apps/knowbase/mixins/generators/content_generator.py +218 -0
  32. django_cfg/apps/knowbase/mixins/generators/field_analyzer.py +76 -0
  33. django_cfg/apps/knowbase/mixins/generators/metadata_generator.py +124 -0
  34. django_cfg/apps/knowbase/mixins/service.py +2 -2
  35. django_cfg/apps/knowbase/services/archive/__init__.py +1 -0
  36. django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +17 -0
  37. django_cfg/apps/knowbase/services/archive/analyzers/complexity_analyzer.py +33 -0
  38. django_cfg/apps/knowbase/services/archive/analyzers/purpose_detector.py +36 -0
  39. django_cfg/apps/knowbase/services/archive/analyzers/quality_analyzer.py +39 -0
  40. django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +103 -0
  41. django_cfg/apps/knowbase/services/archive/chunking/__init__.py +19 -0
  42. django_cfg/apps/knowbase/services/archive/chunking/base.py +81 -0
  43. django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +62 -0
  44. django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +107 -0
  45. django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +248 -0
  46. django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +70 -0
  47. django_cfg/apps/knowbase/services/archive/chunking_service.py +110 -729
  48. django_cfg/apps/knowbase/services/archive/context/__init__.py +14 -0
  49. django_cfg/apps/knowbase/services/archive/context/builders.py +220 -0
  50. django_cfg/apps/knowbase/services/archive/context/models.py +38 -0
  51. django_cfg/apps/knowbase/services/embedding/models.py +18 -14
  52. django_cfg/apps/knowbase/services/embedding/processors.py +6 -3
  53. django_cfg/apps/knowbase/tasks/document_processing.py +11 -3
  54. django_cfg/apps/leads/tests.py +1 -1
  55. django_cfg/apps/payments/admin/api_keys_admin.py +1 -1
  56. django_cfg/apps/payments/admin/balance_admin.py +1 -1
  57. django_cfg/apps/payments/admin/currencies_admin.py +1 -1
  58. django_cfg/apps/payments/admin/payments_admin.py +1 -1
  59. django_cfg/apps/payments/admin/subscriptions_admin.py +1 -1
  60. django_cfg/apps/payments/admin_interface/templates/payments/base.html +59 -126
  61. django_cfg/apps/payments/admin_interface/views/api/payments.py +1 -1
  62. django_cfg/apps/payments/admin_interface/views/api/stats.py +1 -1
  63. django_cfg/apps/payments/admin_interface/views/api/users.py +1 -1
  64. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +1 -1
  65. django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +1 -1
  66. django_cfg/apps/payments/admin_interface/views/base.py +29 -2
  67. django_cfg/apps/payments/apps.py +1 -1
  68. django_cfg/apps/payments/config/django_cfg_integration.py +2 -2
  69. django_cfg/apps/payments/config/helpers.py +3 -2
  70. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +1 -1
  71. django_cfg/apps/payments/management/commands/currency_stats.py +1 -1
  72. django_cfg/apps/payments/management/commands/manage_currencies.py +1 -1
  73. django_cfg/apps/payments/management/commands/manage_providers.py +1 -1
  74. django_cfg/apps/payments/management/commands/process_pending_payments.py +1 -1
  75. django_cfg/apps/payments/management/commands/test_providers.py +1 -1
  76. django_cfg/apps/payments/middleware/api_access.py +1 -1
  77. django_cfg/apps/payments/middleware/rate_limiting.py +1 -1
  78. django_cfg/apps/payments/middleware/usage_tracking.py +1 -1
  79. django_cfg/apps/payments/models/balance.py +2 -2
  80. django_cfg/apps/payments/models/managers/api_key_managers.py +1 -1
  81. django_cfg/apps/payments/models/managers/balance_managers.py +1 -1
  82. django_cfg/apps/payments/models/managers/currency_managers.py +1 -1
  83. django_cfg/apps/payments/models/managers/payment_managers.py +1 -1
  84. django_cfg/apps/payments/models/managers/subscription_managers.py +1 -1
  85. django_cfg/apps/payments/models/payments.py +2 -2
  86. django_cfg/apps/payments/services/cache_service/__init__.py +1 -1
  87. django_cfg/apps/payments/services/cache_service/simple_cache.py +10 -5
  88. django_cfg/apps/payments/services/core/base.py +1 -1
  89. django_cfg/apps/payments/services/core/currency/__init__.py +13 -0
  90. django_cfg/apps/payments/services/core/currency/currency_converter.py +57 -0
  91. django_cfg/apps/payments/services/core/currency/currency_validator.py +61 -0
  92. django_cfg/apps/payments/services/core/operations/__init__.py +15 -0
  93. django_cfg/apps/payments/services/core/operations/payment_canceller.py +100 -0
  94. django_cfg/apps/payments/services/core/operations/payment_creator.py +196 -0
  95. django_cfg/apps/payments/services/core/operations/status_checker.py +100 -0
  96. django_cfg/apps/payments/services/core/payment_service.py +124 -612
  97. django_cfg/apps/payments/services/core/providers/__init__.py +13 -0
  98. django_cfg/apps/payments/services/core/providers/provider_client.py +132 -0
  99. django_cfg/apps/payments/services/core/providers/status_mapper.py +89 -0
  100. django_cfg/apps/payments/services/core/utils/__init__.py +13 -0
  101. django_cfg/apps/payments/services/core/utils/data_converter.py +48 -0
  102. django_cfg/apps/payments/services/core/utils/statistics_calculator.py +69 -0
  103. django_cfg/apps/payments/services/providers/base.py +1 -1
  104. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +3 -3
  105. django_cfg/apps/payments/services/providers/nowpayments/parsers/__init__.py +9 -0
  106. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +23 -0
  107. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/constants.py +23 -0
  108. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/currency_names.py +244 -0
  109. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +511 -0
  110. django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +168 -0
  111. django_cfg/apps/payments/services/providers/nowpayments/provider.py +1 -1
  112. django_cfg/apps/payments/services/providers/nowpayments/sync.py +1 -1
  113. django_cfg/apps/payments/services/providers/registry.py +1 -1
  114. django_cfg/apps/payments/services/providers/sync_service.py +1 -1
  115. django_cfg/apps/payments/signals/__init__.py +1 -1
  116. django_cfg/apps/payments/signals/api_key_signals.py +1 -1
  117. django_cfg/apps/payments/signals/balance_signals.py +1 -1
  118. django_cfg/apps/payments/signals/payment_signals.py +1 -1
  119. django_cfg/apps/payments/signals/subscription_signals.py +1 -1
  120. django_cfg/apps/payments/views/api/api_keys.py +1 -1
  121. django_cfg/apps/payments/views/api/balances.py +1 -1
  122. django_cfg/apps/payments/views/api/base.py +1 -1
  123. django_cfg/apps/payments/views/api/currencies.py +1 -1
  124. django_cfg/apps/payments/views/api/payments.py +1 -1
  125. django_cfg/apps/payments/views/api/subscriptions.py +1 -1
  126. django_cfg/apps/payments/views/api/webhooks.py +1 -1
  127. django_cfg/apps/payments/views/serializers/api_keys.py +1 -1
  128. django_cfg/apps/payments/views/serializers/balances.py +1 -1
  129. django_cfg/apps/payments/views/serializers/currencies.py +1 -1
  130. django_cfg/apps/payments/views/serializers/payments.py +1 -1
  131. django_cfg/apps/payments/views/serializers/subscriptions.py +1 -1
  132. django_cfg/apps/payments/views/serializers/webhooks.py +1 -1
  133. django_cfg/apps/support/admin/support_admin.py +21 -13
  134. django_cfg/apps/support/templates/support/chat/access_denied.html +21 -27
  135. django_cfg/apps/support/templates/support/chat/ticket_chat.html +183 -254
  136. django_cfg/apps/support/utils/support_email_service.py +1 -1
  137. django_cfg/apps/tasks/templates/tasks/layout/base.html +20 -115
  138. django_cfg/apps/tasks/utils/simulator.py +1 -1
  139. django_cfg/apps/tasks/views/dashboard.py +33 -3
  140. django_cfg/apps/urls.py +5 -1
  141. django_cfg/cli/README.md +57 -471
  142. django_cfg/cli/commands/create_project.py +140 -529
  143. django_cfg/cli/main.py +13 -10
  144. django_cfg/core/__init__.py +63 -6
  145. django_cfg/core/base/__init__.py +5 -0
  146. django_cfg/core/base/config_model.py +652 -0
  147. django_cfg/core/builders/__init__.py +11 -0
  148. django_cfg/core/builders/apps_builder.py +258 -0
  149. django_cfg/core/builders/middleware_builder.py +115 -0
  150. django_cfg/core/builders/security_builder.py +96 -0
  151. django_cfg/core/config.py +20 -892
  152. django_cfg/core/constants.py +69 -0
  153. django_cfg/core/environment/__init__.py +9 -0
  154. django_cfg/core/exceptions.py +45 -298
  155. django_cfg/core/generation/__init__.py +51 -0
  156. django_cfg/core/generation/core_generators/__init__.py +0 -0
  157. django_cfg/core/generation/core_generators/settings.py +90 -0
  158. django_cfg/core/generation/core_generators/static.py +82 -0
  159. django_cfg/core/generation/core_generators/templates.py +141 -0
  160. django_cfg/core/generation/data_generators/__init__.py +15 -0
  161. django_cfg/core/generation/data_generators/cache.py +132 -0
  162. django_cfg/core/generation/data_generators/database.py +117 -0
  163. django_cfg/core/generation/generation.py +92 -0
  164. django_cfg/core/generation/integration_generators/__init__.py +21 -0
  165. django_cfg/core/generation/integration_generators/api.py +237 -0
  166. django_cfg/core/generation/integration_generators/sessions.py +65 -0
  167. django_cfg/core/generation/integration_generators/tailwind.py +54 -0
  168. django_cfg/core/generation/integration_generators/tasks.py +92 -0
  169. django_cfg/core/generation/integration_generators/third_party.py +144 -0
  170. django_cfg/core/generation/orchestrator.py +285 -0
  171. django_cfg/core/generation/protocols.py +30 -0
  172. django_cfg/core/generation/security_generators/__init__.py +0 -0
  173. django_cfg/core/generation/utility_generators/__init__.py +24 -0
  174. django_cfg/core/generation/utility_generators/email.py +58 -0
  175. django_cfg/core/generation/utility_generators/i18n.py +66 -0
  176. django_cfg/core/generation/utility_generators/limits.py +58 -0
  177. django_cfg/core/generation/utility_generators/logging.py +66 -0
  178. django_cfg/core/generation/utility_generators/security.py +101 -0
  179. django_cfg/core/generation/utils/__init__.py +0 -0
  180. django_cfg/core/generation/utils/helpers.py +32 -0
  181. django_cfg/core/integration/__init__.py +18 -25
  182. django_cfg/core/integration/display/startup.py +146 -133
  183. django_cfg/core/integration/url_integration.py +13 -2
  184. django_cfg/core/services/__init__.py +5 -0
  185. django_cfg/core/services/config_service.py +121 -0
  186. django_cfg/core/state/__init__.py +9 -0
  187. django_cfg/core/state/registry.py +84 -0
  188. django_cfg/core/types/__init__.py +15 -0
  189. django_cfg/core/types/aliases.py +15 -0
  190. django_cfg/core/types/enums.py +49 -0
  191. django_cfg/dashboard/DEBUG_README.md +105 -0
  192. django_cfg/dashboard/REFACTORING_SUMMARY.md +237 -0
  193. django_cfg/dashboard/__init__.py +24 -0
  194. django_cfg/dashboard/components.py +308 -0
  195. django_cfg/dashboard/debug.py +176 -0
  196. django_cfg/dashboard/management/__init__.py +0 -0
  197. django_cfg/dashboard/management/commands/__init__.py +0 -0
  198. django_cfg/dashboard/management/commands/debug_dashboard.py +109 -0
  199. django_cfg/dashboard/sections/__init__.py +1 -0
  200. django_cfg/dashboard/sections/base.py +128 -0
  201. django_cfg/dashboard/sections/commands.py +32 -0
  202. django_cfg/dashboard/sections/overview.py +394 -0
  203. django_cfg/dashboard/sections/stats.py +48 -0
  204. django_cfg/dashboard/sections/system.py +73 -0
  205. django_cfg/management/commands/check_settings.py +6 -2
  206. django_cfg/management/commands/clear_constance.py +6 -1
  207. django_cfg/management/commands/create_token.py +5 -4
  208. django_cfg/management/commands/generate.py +5 -0
  209. django_cfg/management/commands/list_urls.py +7 -2
  210. django_cfg/management/commands/migrate_all.py +6 -2
  211. django_cfg/management/commands/migrator.py +6 -1
  212. django_cfg/management/commands/rundramatiq.py +6 -1
  213. django_cfg/management/commands/rundramatiq_simulator.py +11 -4
  214. django_cfg/management/commands/runserver_ngrok.py +9 -7
  215. django_cfg/management/commands/script.py +25 -21
  216. django_cfg/management/commands/show_config.py +6 -1
  217. django_cfg/management/commands/show_urls.py +8 -3
  218. django_cfg/management/commands/superuser.py +5 -4
  219. django_cfg/management/commands/task_clear.py +8 -3
  220. django_cfg/management/commands/task_status.py +8 -3
  221. django_cfg/management/commands/test_email.py +6 -1
  222. django_cfg/management/commands/test_telegram.py +6 -1
  223. django_cfg/management/commands/test_twilio.py +6 -1
  224. django_cfg/management/commands/tree.py +7 -4
  225. django_cfg/models/__init__.py +88 -3
  226. django_cfg/models/api/__init__.py +27 -0
  227. django_cfg/models/{api.py → api/config.py} +1 -1
  228. django_cfg/models/api/drf/__init__.py +21 -0
  229. django_cfg/models/api/drf/config.py +101 -0
  230. django_cfg/models/api/drf/redoc.py +31 -0
  231. django_cfg/models/api/drf/spectacular.py +129 -0
  232. django_cfg/models/api/drf/swagger.py +59 -0
  233. django_cfg/models/{api_keys.py → api/keys.py} +16 -6
  234. django_cfg/models/{limits.py → api/limits.py} +0 -1
  235. django_cfg/models/base/__init__.py +14 -0
  236. django_cfg/models/django/__init__.py +16 -0
  237. django_cfg/models/{constance.py → django/constance.py} +1 -1
  238. django_cfg/models/{environment.py → django/environment.py} +1 -1
  239. django_cfg/models/infrastructure/__init__.py +17 -0
  240. django_cfg/models/{cache.py → infrastructure/cache.py} +3 -2
  241. django_cfg/models/infrastructure/database/__init__.py +22 -0
  242. django_cfg/models/infrastructure/database/config.py +265 -0
  243. django_cfg/models/infrastructure/database/converters.py +91 -0
  244. django_cfg/models/infrastructure/database/parsers.py +96 -0
  245. django_cfg/models/infrastructure/database/routing.py +85 -0
  246. django_cfg/models/infrastructure/database/validators.py +170 -0
  247. django_cfg/models/{logging.py → infrastructure/logging.py} +1 -1
  248. django_cfg/models/{security.py → infrastructure/security.py} +2 -2
  249. django_cfg/models/ngrok/__init__.py +11 -0
  250. django_cfg/models/ngrok/auth.py +37 -0
  251. django_cfg/models/ngrok/config.py +77 -0
  252. django_cfg/models/ngrok/tunnel.py +35 -0
  253. django_cfg/models/payments/__init__.py +20 -0
  254. django_cfg/models/payments/api_keys.py +57 -0
  255. django_cfg/models/{payments.py → payments/config.py} +56 -154
  256. django_cfg/models/payments/providers/__init__.py +15 -0
  257. django_cfg/models/payments/providers/base.py +25 -0
  258. django_cfg/models/payments/providers/nowpayments.py +48 -0
  259. django_cfg/models/services/__init__.py +18 -0
  260. django_cfg/models/services/base.py +65 -0
  261. django_cfg/models/{email.py → services/email.py} +1 -1
  262. django_cfg/models/services/telegram.py +172 -0
  263. django_cfg/models/tasks/__init__.py +51 -0
  264. django_cfg/models/tasks/backends.py +250 -0
  265. django_cfg/models/tasks/config.py +314 -0
  266. django_cfg/models/tasks/utils.py +174 -0
  267. django_cfg/modules/base.py +18 -3
  268. django_cfg/modules/django_admin/decorators/actions.py +1 -1
  269. django_cfg/modules/django_admin/decorators/display.py +1 -1
  270. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +1 -1
  271. django_cfg/modules/django_cfg_rpc_client/README.md +346 -0
  272. django_cfg/modules/django_cfg_rpc_client/__init__.py +51 -0
  273. django_cfg/modules/django_cfg_rpc_client/client.py +540 -0
  274. django_cfg/modules/django_cfg_rpc_client/config.py +207 -0
  275. django_cfg/modules/django_cfg_rpc_client/dashboard/README.md +517 -0
  276. django_cfg/modules/django_cfg_rpc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
  277. django_cfg/modules/django_cfg_rpc_client/dashboard/__init__.py +11 -0
  278. django_cfg/modules/django_cfg_rpc_client/dashboard/apps.py +22 -0
  279. django_cfg/modules/django_cfg_rpc_client/dashboard/monitor.py +435 -0
  280. django_cfg/modules/django_cfg_rpc_client/dashboard/static/django_cfg_rpc_dashboard/js/dashboard.js +373 -0
  281. django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/base.html +76 -0
  282. django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/dashboard.html +200 -0
  283. django_cfg/modules/django_cfg_rpc_client/dashboard/urls.py +22 -0
  284. django_cfg/modules/django_cfg_rpc_client/dashboard/urls_admin.py +9 -0
  285. django_cfg/modules/django_cfg_rpc_client/dashboard/views.py +251 -0
  286. django_cfg/modules/django_cfg_rpc_client/exceptions.py +201 -0
  287. django_cfg/modules/django_drf_theme/CHANGELOG.md +210 -0
  288. django_cfg/modules/django_drf_theme/EXAMPLE.md +465 -0
  289. django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +232 -0
  290. django_cfg/modules/django_drf_theme/README.md +207 -0
  291. django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +274 -0
  292. django_cfg/modules/django_drf_theme/__init__.py +23 -0
  293. django_cfg/modules/django_drf_theme/apps.py +15 -0
  294. django_cfg/modules/django_drf_theme/renderers.py +58 -0
  295. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/api.html +375 -0
  296. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/base.html +938 -0
  297. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/filter_form.html +132 -0
  298. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/raw_data_form.html +123 -0
  299. django_cfg/modules/django_drf_theme/templatetags/__init__.py +1 -0
  300. django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +57 -0
  301. django_cfg/modules/django_email/__init__.py +14 -0
  302. django_cfg/modules/{django_email.py → django_email/service.py} +78 -113
  303. django_cfg/modules/django_email/utils.py +40 -0
  304. django_cfg/modules/django_health/__init__.py +9 -0
  305. django_cfg/modules/{django_health.py → django_health/service.py} +23 -21
  306. django_cfg/modules/django_llm/llm/client.py +155 -550
  307. django_cfg/modules/django_llm/llm/embeddings/__init__.py +13 -0
  308. django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +106 -0
  309. django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +79 -0
  310. django_cfg/modules/django_llm/llm/models_api/__init__.py +9 -0
  311. django_cfg/modules/django_llm/llm/models_api/models_query.py +163 -0
  312. django_cfg/modules/django_llm/llm/providers/__init__.py +15 -0
  313. django_cfg/modules/django_llm/llm/providers/config_builder.py +103 -0
  314. django_cfg/modules/django_llm/llm/providers/provider_manager.py +148 -0
  315. django_cfg/modules/django_llm/llm/providers/provider_selector.py +60 -0
  316. django_cfg/modules/django_llm/llm/requests/__init__.py +15 -0
  317. django_cfg/modules/django_llm/llm/requests/cache_manager.py +170 -0
  318. django_cfg/modules/django_llm/llm/requests/chat_handler.py +199 -0
  319. django_cfg/modules/django_llm/llm/requests/embedding_handler.py +113 -0
  320. django_cfg/modules/django_llm/llm/responses/__init__.py +9 -0
  321. django_cfg/modules/django_llm/llm/responses/response_builder.py +131 -0
  322. django_cfg/modules/django_llm/llm/stats/__init__.py +9 -0
  323. django_cfg/modules/django_llm/llm/stats/stats_manager.py +107 -0
  324. django_cfg/modules/django_llm/translator/detectors/__init__.py +13 -0
  325. django_cfg/modules/django_llm/translator/detectors/language_detector.py +90 -0
  326. django_cfg/modules/django_llm/translator/detectors/script_detector.py +153 -0
  327. django_cfg/modules/django_llm/translator/stats/__init__.py +11 -0
  328. django_cfg/modules/django_llm/translator/stats/stats_tracker.py +85 -0
  329. django_cfg/modules/django_llm/translator/translator.py +150 -603
  330. django_cfg/modules/django_llm/translator/translators/__init__.py +15 -0
  331. django_cfg/modules/django_llm/translator/translators/json_translator.py +316 -0
  332. django_cfg/modules/django_llm/translator/translators/text_translator.py +139 -0
  333. django_cfg/modules/django_llm/translator/utils/__init__.py +13 -0
  334. django_cfg/modules/django_llm/translator/utils/prompt_builder.py +110 -0
  335. django_cfg/modules/django_llm/translator/utils/text_utils.py +114 -0
  336. django_cfg/modules/django_logging/FIXES_SUMMARY.md +276 -0
  337. django_cfg/modules/django_logging/LOGGING_GUIDE.md +504 -0
  338. django_cfg/modules/django_logging/__init__.py +14 -0
  339. django_cfg/modules/{django_logger.py → django_logging/django_logger.py} +13 -13
  340. django_cfg/modules/{logger.py → django_logging/logger.py} +14 -4
  341. django_cfg/modules/django_ngrok/__init__.py +39 -0
  342. django_cfg/modules/{django_ngrok.py → django_ngrok/service.py} +14 -42
  343. django_cfg/modules/django_rpc_old/POETRY.md +344 -0
  344. django_cfg/modules/django_rpc_old/README.md +397 -0
  345. django_cfg/modules/django_rpc_old/TESTING.md +358 -0
  346. django_cfg/modules/django_rpc_old/__init__.py +39 -0
  347. django_cfg/modules/django_rpc_old/client.py +531 -0
  348. django_cfg/modules/django_rpc_old/config.py +279 -0
  349. django_cfg/modules/django_rpc_old/exceptions.py +172 -0
  350. django_cfg/modules/django_tailwind/README.md +478 -0
  351. django_cfg/modules/django_tailwind/__init__.py +7 -0
  352. django_cfg/modules/django_tailwind/apps.py +10 -0
  353. django_cfg/modules/django_tailwind/templates/django_tailwind/app.html +5 -0
  354. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +117 -0
  355. django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +124 -0
  356. django_cfg/modules/django_tailwind/templates/django_tailwind/components/theme_toggle.html +54 -0
  357. django_cfg/modules/django_tailwind/templates/django_tailwind/components/user_menu.html +116 -0
  358. django_cfg/modules/django_tailwind/templates/django_tailwind/simple.html +46 -0
  359. django_cfg/modules/django_tailwind/templatetags/__init__.py +1 -0
  360. django_cfg/modules/django_tailwind/templatetags/tailwind_info.py +185 -0
  361. django_cfg/modules/django_tasks/__init__.py +29 -0
  362. django_cfg/modules/django_tasks/factory.py +127 -0
  363. django_cfg/modules/{django_tasks.py → django_tasks/service.py} +45 -274
  364. django_cfg/modules/django_tasks/settings.py +107 -0
  365. django_cfg/modules/django_telegram/__init__.py +29 -0
  366. django_cfg/modules/{django_telegram.py → django_telegram/service.py} +45 -113
  367. django_cfg/modules/django_telegram/utils.py +62 -0
  368. django_cfg/modules/django_twilio/__init__.py +54 -107
  369. django_cfg/modules/django_twilio/_imports.py +30 -0
  370. django_cfg/modules/django_twilio/base.py +192 -0
  371. django_cfg/modules/django_twilio/email_otp.py +227 -0
  372. django_cfg/modules/django_twilio/sendgrid_service.py +1 -1
  373. django_cfg/modules/django_twilio/simple_service.py +1 -2
  374. django_cfg/modules/django_twilio/sms.py +94 -0
  375. django_cfg/modules/django_twilio/twilio_service.py +2 -3
  376. django_cfg/modules/django_twilio/unified.py +310 -0
  377. django_cfg/modules/django_twilio/utils.py +190 -0
  378. django_cfg/modules/django_twilio/whatsapp.py +137 -0
  379. django_cfg/modules/django_unfold/callbacks/base.py +198 -7
  380. django_cfg/modules/django_unfold/callbacks/main.py +102 -10
  381. django_cfg/modules/django_unfold/dashboard.py +65 -43
  382. django_cfg/modules/django_unfold/models/config.py +13 -12
  383. django_cfg/modules/django_unfold/models/navigation.py +8 -3
  384. django_cfg/modules/django_unfold/models/tabs.py +2 -2
  385. django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +102 -0
  386. django_cfg/registry/core.py +24 -26
  387. django_cfg/registry/modules.py +5 -2
  388. django_cfg/registry/services.py +20 -3
  389. django_cfg/registry/third_party.py +8 -8
  390. django_cfg/static/admin/css/dashboard.css +260 -0
  391. django_cfg/static/admin/js/commands.js +171 -0
  392. django_cfg/static/admin/js/dashboard.js +126 -0
  393. django_cfg/templates/admin/components/management_commands.js +375 -0
  394. django_cfg/templates/admin/components/progress_bar.html +18 -23
  395. django_cfg/templates/admin/index.html +48 -20
  396. django_cfg/templates/admin/index_new.html +106 -0
  397. django_cfg/templates/admin/layouts/base_dashboard.html +60 -0
  398. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +1 -20
  399. django_cfg/templates/admin/sections/commands_section.html +626 -0
  400. django_cfg/templates/admin/sections/overview_section.html +112 -0
  401. django_cfg/templates/admin/sections/stats_section.html +35 -0
  402. django_cfg/templates/admin/sections/system_section.html +99 -0
  403. django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +322 -0
  404. django_cfg/templates/admin/snippets/components/activity_tracker.html +85 -47
  405. django_cfg/templates/admin/snippets/components/charts_section.html +154 -64
  406. django_cfg/templates/admin/snippets/components/django_commands.html +3 -3
  407. django_cfg/templates/admin/snippets/components/recent_activity_improved.html +25 -0
  408. django_cfg/templates/admin/snippets/components/recent_users_table.html +1 -1
  409. django_cfg/templates/admin/snippets/components/system_metrics.html +179 -93
  410. django_cfg/templates/admin/snippets/zones/zones_table.html +2 -2
  411. django_cfg/templatetags/django_cfg.py +7 -1
  412. django_cfg/utils/smart_defaults.py +4 -4
  413. django_cfg-1.4.0.dist-info/METADATA +920 -0
  414. {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/RECORD +425 -196
  415. django_cfg/apps/accounts/utils/auth_email_service.py +0 -84
  416. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +0 -879
  417. django_cfg/core/generation.py +0 -621
  418. django_cfg/management/commands/validate_config.py +0 -189
  419. django_cfg/models/database.py +0 -480
  420. django_cfg/models/drf.py +0 -272
  421. django_cfg/models/ngrok.py +0 -122
  422. django_cfg/models/services.py +0 -440
  423. django_cfg/models/tasks.py +0 -550
  424. django_cfg/modules/django_twilio/service.py +0 -942
  425. django_cfg/template_archive/django_sample.zip +0 -0
  426. django_cfg/templates/rest_framework/api.html +0 -12
  427. django_cfg/utils/toolkit.py +0 -703
  428. django_cfg-1.3.11.dist-info/METADATA +0 -1029
  429. /django_cfg/apps/accounts/management/commands/{test_otp.py → otp_test.py} +0 -0
  430. /django_cfg/core/{environment.py → environment/detector.py} +0 -0
  431. /django_cfg/models/{cors.py → api/cors.py} +0 -0
  432. /django_cfg/models/{jwt.py → api/jwt.py} +0 -0
  433. /django_cfg/models/{base.py → base/config.py} +0 -0
  434. /django_cfg/models/{cfg.py → base/module.py} +0 -0
  435. /django_cfg/models/{revolution.py → django/revolution.py} +0 -0
  436. /django_cfg/modules/{dramatiq_setup.py → django_tasks/dramatiq_setup.py} +0 -0
  437. {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/WHEEL +0 -0
  438. {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/entry_points.txt +0 -0
  439. {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,626 @@
1
+ {% load unfold %}
2
+
3
+ <!-- Commands Section -->
4
+ <div class="space-y-8">
5
+ <div class="flex items-center justify-between mb-6">
6
+ <div>
7
+ <h1 class="text-2xl font-bold text-font-important-light dark:text-font-important-dark">{{ title|default:"Management Commands" }}</h1>
8
+ <p class="text-font-default-light dark:text-font-default-dark mt-2">
9
+ Execute Django management commands directly from the dashboard
10
+ </p>
11
+ </div>
12
+ <div class="text-sm text-font-subtle-light dark:text-font-subtle-dark">
13
+ Total: <span id="commands-total" class="font-mono font-semibold text-font-important-light dark:text-font-important-dark">{{ data.commands|length }}</span> commands
14
+ </div>
15
+ </div>
16
+
17
+ <!-- Search Box -->
18
+ <div class="flex items-center gap-3 mb-6">
19
+ <div class="relative flex-1 max-w-md">
20
+ <span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-base-400 dark:text-base-500">search</span>
21
+ <input
22
+ type="text"
23
+ id="command-search"
24
+ placeholder="Search commands..."
25
+ class="w-full pl-10 pr-10 py-2 border border-base-200 dark:border-base-700 rounded-default bg-white dark:bg-base-800 text-font-important-light dark:text-font-important-dark placeholder-font-subtle-light dark:placeholder-font-subtle-dark focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent"
26
+ />
27
+ <button
28
+ id="clear-search"
29
+ class="hidden absolute right-3 top-1/2 -translate-y-1/2 text-base-400 dark:text-base-500 hover:text-base-600 dark:hover:text-base-300"
30
+ onclick="clearSearch()"
31
+ >
32
+ <span class="material-symbols-outlined text-lg">close</span>
33
+ </button>
34
+ </div>
35
+ </div>
36
+
37
+ <!-- Commands by Category -->
38
+ {% if data.categories %}
39
+ <div class="flex flex-col gap-6">
40
+ {% for category, category_commands in data.categories.items %}
41
+ {% if category_commands %}
42
+ <div class="category-block bg-gradient-to-br from-white to-base-50 dark:from-base-800 dark:to-base-900 rounded-default shadow-md border border-base-200 dark:border-base-700 overflow-hidden">
43
+ <div class="p-6 border-b border-base-200 dark:border-base-700 category-toggle cursor-pointer hover:bg-base-100/50 dark:hover:bg-base-900/30 transition-all duration-200"
44
+ data-category="{{ category }}">
45
+ <div class="w-full flex items-center justify-between">
46
+ <h3 class="text-lg font-semibold text-font-important-light dark:text-font-important-dark flex items-center">
47
+ <div class="w-10 h-10 rounded-lg bg-primary-100 dark:bg-primary-900/30 flex items-center justify-center mr-3">
48
+ <span class="material-symbols-outlined text-primary-600 dark:text-primary-400">
49
+ {% if category == 'django_cfg' %}settings
50
+ {% elif category == 'django_core' %}apps
51
+ {% elif category == 'third_party' %}extension
52
+ {% else %}folder{% endif %}
53
+ </span>
54
+ </div>
55
+ <div>
56
+ <div class="flex items-center gap-2">
57
+ {{ category|title }} Commands
58
+ <span class="px-2 py-0.5 text-xs font-medium rounded-full bg-base-200 dark:bg-base-700 text-font-default-light dark:text-font-default-dark category-count">
59
+ {{ category_commands|length }}
60
+ </span>
61
+ </div>
62
+ </div>
63
+ </h3>
64
+ <span class="material-symbols-outlined text-base-400 dark:text-base-500 toggle-icon transition-transform duration-200 select-none">expand_more</span>
65
+ </div>
66
+ </div>
67
+ <div class="p-6 category-content bg-base-50/30 dark:bg-base-900/30" data-category="{{ category }}" style="display: none;">
68
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
69
+ {% for cmd in category_commands %}
70
+ <button type="button"
71
+ class="command-btn command-item text-left p-4 rounded-default border border-base-200/60 dark:border-base-700/60 bg-white dark:bg-base-800 hover:border-base-300 dark:hover:border-base-600 hover:bg-white/80 dark:hover:bg-base-800/80 transition-all duration-200 group"
72
+ data-command="{{ cmd.name }}"
73
+ data-app="{{ cmd.app }}"
74
+ data-description="{{ cmd.description|default:'' }}">
75
+ <div class="flex items-center gap-3">
76
+ <div class="flex-shrink-0">
77
+ <span class="material-symbols-outlined text-primary-500 dark:text-primary-400 text-xl group-hover:text-primary-600 dark:group-hover:text-primary-300 transition-colors">terminal</span>
78
+ </div>
79
+ <div class="flex-1 grow min-w-0">
80
+ <p class="font-mono text-sm text-font-important-light dark:text-font-important-dark font-semibold command-name truncate">{{ cmd.name }}</p>
81
+ {% if cmd.description %}
82
+ <p class="text-xs text-font-default-light dark:text-font-default-dark mt-1 line-clamp-2">{{ cmd.description }}</p>
83
+ {% endif %}
84
+ {% if cmd.app %}
85
+ <p class="text-xs text-font-subtle-light dark:text-font-subtle-dark mt-1 truncate">
86
+ <span class="opacity-60">from</span> {{ cmd.app }}
87
+ </p>
88
+ {% endif %}
89
+ </div>
90
+ <div class="flex-shrink-0">
91
+ <span class="material-symbols-outlined text-base-400 dark:text-base-600 group-hover:text-primary-500 dark:group-hover:text-primary-400 transition-colors text-2xl">chevron_right</span>
92
+ </div>
93
+ </div>
94
+ </button>
95
+ {% endfor %}
96
+ </div>
97
+ </div>
98
+ </div>
99
+ {% endif %}
100
+ {% endfor %}
101
+ </div>
102
+ {% else %}
103
+ <!-- Fallback: All Commands List -->
104
+ <div class="bg-white dark:bg-base-800 rounded-default shadow-sm border border-base-200 dark:border-base-700">
105
+ <div class="p-6 border-b border-base-200 dark:border-base-700">
106
+ <h3 class="text-lg font-semibold text-font-important-light dark:text-font-important-dark flex items-center">
107
+ <span class="material-symbols-outlined text-primary-500 mr-2">list</span>
108
+ All Commands
109
+ </h3>
110
+ </div>
111
+ <div class="p-6">
112
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
113
+ {% for cmd in data.commands %}
114
+ <button type="button"
115
+ class="command-btn text-left p-4 rounded-default border border-base-200 dark:border-base-700 bg-white dark:bg-base-800 hover:bg-base-100 dark:hover:bg-white/[.04] transition-colors"
116
+ data-command="{{ cmd.name }}">
117
+ <div class="flex items-center justify-between">
118
+ <div>
119
+ <p class="font-mono text-sm text-font-important-light dark:text-font-important-dark font-semibold">{{ cmd.name }}</p>
120
+ {% if cmd.app %}
121
+ <p class="text-xs text-font-subtle-light dark:text-font-subtle-dark mt-1">{{ cmd.app }}</p>
122
+ {% endif %}
123
+ </div>
124
+ <span class="material-symbols-outlined text-primary-500">play_arrow</span>
125
+ </div>
126
+ </button>
127
+ {% endfor %}
128
+ </div>
129
+ </div>
130
+ </div>
131
+ {% endif %}
132
+
133
+ <!-- Confirm Modal -->
134
+ <div id="confirm-modal" class="hidden backdrop-blur-xs bg-base-900/80 fixed inset-0 p-4 lg:p-32 z-[1000]">
135
+ <div class="bg-white dark:bg-base-800 rounded-default shadow-lg border border-base-200 dark:border-base-700 max-w-3xl mx-auto w-full">
136
+ <div class="px-4 py-3 border-b border-base-200 dark:border-base-700">
137
+ <h3 class="text-lg font-semibold text-font-important-light dark:text-font-important-dark flex items-center gap-2">
138
+ <span class="material-symbols-outlined text-amber-500 dark:text-amber-400">warning</span>
139
+ Confirm Command Execution
140
+ </h3>
141
+ </div>
142
+ <div class="p-6">
143
+ <p class="text-font-default-light dark:text-font-default-dark mb-4">
144
+ Are you sure you want to execute the following command?
145
+ </p>
146
+ <div class="bg-base-100 dark:bg-base-900 rounded-default p-4 border border-base-200 dark:border-base-700">
147
+ <div class="flex items-start gap-3">
148
+ <span class="material-symbols-outlined text-primary-600 dark:text-primary-400 text-xl">terminal</span>
149
+ <div class="flex-1 min-w-0">
150
+ <p class="font-mono text-sm font-semibold text-font-important-light dark:text-font-important-dark" id="confirm-command-name"></p>
151
+ <p class="text-xs text-font-subtle-light dark:text-font-subtle-dark mt-2" id="confirm-command-app"></p>
152
+ <p class="text-xs text-font-default-light dark:text-font-default-dark mt-1" id="confirm-command-desc"></p>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ <div class="px-4 py-3 border-t border-base-200 dark:border-base-800 flex items-center justify-end gap-3">
158
+ <button type="button" id="cancel-confirm" class="px-4 py-2 text-font-default-light dark:text-font-default-dark hover:bg-base-100 dark:hover:bg-base-700 rounded-default transition-colors">
159
+ Cancel
160
+ </button>
161
+ <button type="button" id="execute-confirm" class="px-4 py-2 bg-primary-600 text-white rounded-default hover:bg-primary-700 transition-colors font-medium">
162
+ Execute Command
163
+ </button>
164
+ </div>
165
+ </div>
166
+ </div>
167
+
168
+ <!-- Command Output Modal -->
169
+ <div id="command-modal" class="hidden backdrop-blur-xs bg-base-900/80 flex flex-col fixed inset-0 p-4 lg:p-32 z-[1000]">
170
+ <div class="bg-white dark:bg-base-800 flex flex-col max-w-3xl min-h-0 mx-auto overflow-hidden rounded-default shadow-lg w-full">
171
+ <div class="flex items-center justify-between px-4 py-3 border-b border-base-200 dark:border-base-700">
172
+ <h3 class="text-lg font-semibold text-font-important-light dark:text-font-important-dark flex items-center gap-2">
173
+ <span class="material-symbols-outlined text-primary-600 dark:text-primary-400">terminal</span>
174
+ <span id="modal-command-name" class="font-mono"></span>
175
+ </h3>
176
+ <button type="button" id="close-modal" class="text-base-400 dark:text-base-500 hover:text-base-600 dark:hover:text-base-300 transition-colors">
177
+ <span class="material-symbols-outlined">close</span>
178
+ </button>
179
+ </div>
180
+ <div class="grow overflow-y-auto overflow-x-hidden w-full" data-simplebar id="output-container">
181
+ <div class="p-4">
182
+ <pre id="command-output" class="bg-base-900 dark:bg-black text-green-400 p-4 rounded-default font-mono text-xs leading-relaxed whitespace-pre overflow-x-auto"></pre>
183
+ </div>
184
+ </div>
185
+ <div class="px-4 py-3 border-t border-base-200 dark:border-base-700">
186
+ <div class="flex items-center justify-between">
187
+ <div id="command-status" class="text-sm font-medium"></div>
188
+ <button type="button" id="copy-output" class="px-4 py-2 bg-primary-600 text-white rounded-default hover:bg-primary-700 transition-colors flex items-center gap-2 font-medium">
189
+ <span class="material-symbols-outlined text-base">content_copy</span>
190
+ Copy Output
191
+ </button>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <!-- JavaScript for Commands Section -->
199
+ <script>
200
+ document.addEventListener('DOMContentLoaded', function() {
201
+ // Category toggle functionality
202
+ const categoryToggles = document.querySelectorAll('.category-toggle');
203
+ categoryToggles.forEach(toggle => {
204
+ toggle.addEventListener('click', function() {
205
+ const category = this.dataset.category;
206
+ const content = document.querySelector(`.category-content[data-category="${category}"]`);
207
+ const icon = this.querySelector('.toggle-icon');
208
+
209
+ if (content.style.display === 'none' || !content.style.display) {
210
+ content.style.display = 'block';
211
+ icon.textContent = 'expand_less';
212
+ } else {
213
+ content.style.display = 'none';
214
+ icon.textContent = 'expand_more';
215
+ }
216
+ });
217
+
218
+ // Initialize - start collapsed
219
+ const category = toggle.dataset.category;
220
+ const content = document.querySelector(`.category-content[data-category="${category}"]`);
221
+ if (content) {
222
+ content.style.display = 'none';
223
+ }
224
+ });
225
+
226
+ // Command click handlers - show confirm first
227
+ const commandButtons = document.querySelectorAll('.command-btn');
228
+ commandButtons.forEach(btn => {
229
+ btn.addEventListener('click', function() {
230
+ const commandName = this.dataset.command;
231
+ const commandApp = this.dataset.app || '';
232
+ const commandDesc = this.dataset.description || '';
233
+ showConfirmModal(commandName, commandApp, commandDesc);
234
+ });
235
+ });
236
+
237
+ // Confirm modal handlers
238
+ const confirmModal = document.getElementById('confirm-modal');
239
+ const cancelConfirm = document.getElementById('cancel-confirm');
240
+ const executeConfirm = document.getElementById('execute-confirm');
241
+
242
+ if (cancelConfirm) {
243
+ cancelConfirm.addEventListener('click', function() {
244
+ confirmModal.classList.add('hidden');
245
+ });
246
+ }
247
+
248
+ if (executeConfirm) {
249
+ executeConfirm.addEventListener('click', function() {
250
+ const commandName = document.getElementById('confirm-command-name').textContent;
251
+ confirmModal.classList.add('hidden');
252
+ executeCommand(commandName);
253
+ });
254
+ }
255
+
256
+ // Close confirm modal on background click
257
+ if (confirmModal) {
258
+ confirmModal.addEventListener('click', function(e) {
259
+ if (e.target === confirmModal) {
260
+ confirmModal.classList.add('hidden');
261
+ }
262
+ });
263
+ }
264
+
265
+ // Output Modal close handlers
266
+ const outputModal = document.getElementById('command-modal');
267
+ const closeBtn = document.getElementById('close-modal');
268
+
269
+ if (closeBtn) {
270
+ closeBtn.addEventListener('click', function() {
271
+ outputModal.classList.add('hidden');
272
+ });
273
+ }
274
+
275
+ // Close output modal on background click
276
+ if (outputModal) {
277
+ outputModal.addEventListener('click', function(e) {
278
+ if (e.target === outputModal) {
279
+ outputModal.classList.add('hidden');
280
+ }
281
+ });
282
+ }
283
+
284
+ // Copy output functionality
285
+ const copyBtn = document.getElementById('copy-output');
286
+ if (copyBtn) {
287
+ copyBtn.addEventListener('click', function() {
288
+ const output = document.getElementById('command-output');
289
+ if (output) {
290
+ navigator.clipboard.writeText(output.textContent).then(function() {
291
+ const originalText = copyBtn.innerHTML;
292
+ copyBtn.innerHTML = '<span class="material-symbols-outlined mr-2">check</span>Copied!';
293
+ setTimeout(function() {
294
+ copyBtn.innerHTML = originalText;
295
+ }, 2000);
296
+ }).catch(function(err) {
297
+ console.error('Could not copy text: ', err);
298
+ });
299
+ }
300
+ });
301
+ }
302
+
303
+ // Escape key to close modals
304
+ document.addEventListener('keydown', function(e) {
305
+ if (e.key === 'Escape') {
306
+ if (confirmModal && !confirmModal.classList.contains('hidden')) {
307
+ confirmModal.classList.add('hidden');
308
+ }
309
+ if (outputModal && !outputModal.classList.contains('hidden')) {
310
+ outputModal.classList.add('hidden');
311
+ }
312
+ }
313
+ });
314
+
315
+ // Search functionality
316
+ const searchInput = document.getElementById('command-search');
317
+ const clearSearchBtn = document.getElementById('clear-search');
318
+
319
+ if (searchInput) {
320
+ searchInput.addEventListener('input', function(e) {
321
+ const query = e.target.value.toLowerCase().trim();
322
+ filterCommands(query);
323
+
324
+ // Show/hide clear button
325
+ if (query) {
326
+ clearSearchBtn.classList.remove('hidden');
327
+ } else {
328
+ clearSearchBtn.classList.add('hidden');
329
+ }
330
+ });
331
+ }
332
+ });
333
+
334
+ // Search/filter commands
335
+ function filterCommands(query) {
336
+ const categoryBlocks = document.querySelectorAll('.category-block');
337
+ let totalVisible = 0;
338
+
339
+ categoryBlocks.forEach(block => {
340
+ const commands = block.querySelectorAll('.command-item');
341
+ const categoryCount = block.querySelector('.category-count');
342
+ let visibleCount = 0;
343
+
344
+ commands.forEach(cmd => {
345
+ const commandName = cmd.querySelector('.command-name').textContent.toLowerCase();
346
+ const commandApp = cmd.dataset.app ? cmd.dataset.app.toLowerCase() : '';
347
+ const commandDesc = cmd.dataset.description ? cmd.dataset.description.toLowerCase() : '';
348
+
349
+ if (!query || commandName.includes(query) || commandApp.includes(query) || commandDesc.includes(query)) {
350
+ cmd.style.display = 'block';
351
+ visibleCount++;
352
+ totalVisible++;
353
+ } else {
354
+ cmd.style.display = 'none';
355
+ }
356
+ });
357
+
358
+ // Update category count
359
+ if (categoryCount) {
360
+ categoryCount.textContent = `(${visibleCount})`;
361
+ }
362
+
363
+ // Hide category if no visible commands
364
+ if (visibleCount === 0) {
365
+ block.style.display = 'none';
366
+ } else {
367
+ block.style.display = 'block';
368
+
369
+ // Auto-expand categories when searching
370
+ if (query) {
371
+ const content = block.querySelector('.category-content');
372
+ const icon = block.querySelector('.toggle-icon');
373
+ if (content && icon) {
374
+ content.style.display = 'block';
375
+ icon.textContent = 'expand_less';
376
+ }
377
+ }
378
+ }
379
+ });
380
+
381
+ // Update total commands count
382
+ const totalCounter = document.getElementById('commands-total');
383
+ if (totalCounter) {
384
+ totalCounter.textContent = totalVisible;
385
+ }
386
+ }
387
+
388
+ // Clear search
389
+ function clearSearch() {
390
+ const searchInput = document.getElementById('command-search');
391
+ const clearBtn = document.getElementById('clear-search');
392
+ const categoryBlocks = document.querySelectorAll('.category-block');
393
+ const totalCounter = document.getElementById('commands-total');
394
+
395
+ // Clear input
396
+ if (searchInput) {
397
+ searchInput.value = '';
398
+ }
399
+
400
+ // Hide clear button
401
+ if (clearBtn) {
402
+ clearBtn.classList.add('hidden');
403
+ }
404
+
405
+ // Reset all blocks
406
+ categoryBlocks.forEach(block => {
407
+ block.style.display = 'block';
408
+ const commands = block.querySelectorAll('.command-item');
409
+ const categoryCount = block.querySelector('.category-count');
410
+
411
+ // Show all commands
412
+ commands.forEach(cmd => {
413
+ cmd.style.display = 'block';
414
+ });
415
+
416
+ // Reset category count
417
+ if (categoryCount) {
418
+ const originalCount = commands.length;
419
+ categoryCount.textContent = `(${originalCount})`;
420
+ }
421
+
422
+ // Collapse categories
423
+ const content = block.querySelector('.category-content');
424
+ const icon = block.querySelector('.toggle-icon');
425
+ if (content && icon) {
426
+ content.style.display = 'none';
427
+ icon.textContent = 'expand_more';
428
+ }
429
+ });
430
+
431
+ // Reset total
432
+ if (totalCounter) {
433
+ const allCommands = document.querySelectorAll('.command-item');
434
+ totalCounter.textContent = allCommands.length;
435
+ }
436
+ }
437
+
438
+ // Show confirm modal
439
+ function showConfirmModal(commandName, commandApp, commandDesc) {
440
+ const confirmModal = document.getElementById('confirm-modal');
441
+ const confirmCommandName = document.getElementById('confirm-command-name');
442
+ const confirmCommandApp = document.getElementById('confirm-command-app');
443
+ const confirmCommandDesc = document.getElementById('confirm-command-desc');
444
+
445
+ if (!confirmModal || !confirmCommandName) {
446
+ console.error('Confirm modal elements not found');
447
+ return;
448
+ }
449
+
450
+ confirmCommandName.textContent = commandName;
451
+ confirmCommandApp.textContent = commandApp ? `from ${commandApp}` : '';
452
+ confirmCommandDesc.textContent = commandDesc || '';
453
+
454
+ confirmModal.classList.remove('hidden');
455
+ }
456
+
457
+ // Execute command function with SSE streaming
458
+ function executeCommand(commandName) {
459
+ const modal = document.getElementById('command-modal');
460
+ const modalCommandName = document.getElementById('modal-command-name');
461
+ const commandOutput = document.getElementById('command-output');
462
+ const commandStatus = document.getElementById('command-status');
463
+
464
+ if (!modal || !modalCommandName || !commandOutput || !commandStatus) {
465
+ console.error('Command modal elements not found');
466
+ return;
467
+ }
468
+
469
+ // Show modal and initialize
470
+ modalCommandName.textContent = commandName;
471
+ commandOutput.innerHTML = '';
472
+ commandStatus.textContent = 'Executing...';
473
+ commandStatus.className = 'text-sm text-primary-600 dark:text-primary-400';
474
+ modal.classList.remove('hidden');
475
+
476
+ // Execute command via API with SSE streaming
477
+ fetch('/cfg/commands/execute/', {
478
+ method: 'POST',
479
+ headers: {
480
+ 'Content-Type': 'application/json',
481
+ 'X-CSRFToken': getCookie('csrftoken')
482
+ },
483
+ body: JSON.stringify({
484
+ command: commandName,
485
+ args: [],
486
+ options: {}
487
+ })
488
+ })
489
+ .then(response => {
490
+ if (!response.ok) {
491
+ throw new Error(`HTTP error! status: ${response.status}`);
492
+ }
493
+
494
+ const reader = response.body.getReader();
495
+ const decoder = new TextDecoder();
496
+
497
+ function readStream() {
498
+ return reader.read().then(({done, value}) => {
499
+ if (done) return;
500
+
501
+ const chunk = decoder.decode(value);
502
+ const lines = chunk.split('\n');
503
+
504
+ lines.forEach(line => {
505
+ if (line.startsWith('data: ')) {
506
+ try {
507
+ const data = JSON.parse(line.slice(6));
508
+ handleCommandData(data);
509
+ } catch (e) {
510
+ console.error('Error parsing command data:', e, line);
511
+ }
512
+ }
513
+ });
514
+
515
+ return readStream();
516
+ });
517
+ }
518
+
519
+ return readStream();
520
+ })
521
+ .catch(error => {
522
+ console.error('Error executing command:', error);
523
+ addLogLine(commandOutput, `\n❌ Error: ${error.message}`, 'error');
524
+ commandStatus.textContent = '❌ Error';
525
+ commandStatus.className = 'text-sm text-red-500 dark:text-red-400';
526
+ });
527
+ }
528
+
529
+ // Handle SSE command data
530
+ function handleCommandData(data) {
531
+ const output = document.getElementById('command-output');
532
+ const status = document.getElementById('command-status');
533
+
534
+ if (!output || !status) return;
535
+
536
+ switch (data.type) {
537
+ case 'start':
538
+ output.innerHTML = '';
539
+ addLogLine(output, `🚀 Starting command: ${data.command}`, 'info');
540
+ const args = (data.args && Array.isArray(data.args)) ? data.args.join(' ') : 'none';
541
+ addLogLine(output, `📝 Arguments: ${args}`, 'info');
542
+ addLogLine(output, '', 'spacer');
543
+ status.textContent = 'Executing...';
544
+ status.className = 'text-sm text-primary-600 dark:text-primary-400';
545
+ break;
546
+ case 'output':
547
+ addLogLine(output, data.line, 'output');
548
+ scrollToBottom(document.getElementById('output-container'));
549
+ break;
550
+ case 'complete':
551
+ const success = data.return_code === 0;
552
+ status.textContent = success ? '✅ Success' : '❌ Failed';
553
+ status.className = success
554
+ ? 'text-sm text-green-500 dark:text-green-400'
555
+ : 'text-sm text-red-500 dark:text-red-400';
556
+
557
+ addLogLine(output, '', 'spacer');
558
+ let completionMessage = `${success ? '✅' : '❌'} Command completed with exit code: ${data.return_code}`;
559
+ if (data.execution_time) {
560
+ completionMessage += ` (${data.execution_time}s)`;
561
+ }
562
+ addLogLine(output, completionMessage, success ? 'success' : 'error');
563
+ scrollToBottom(document.getElementById('output-container'));
564
+ break;
565
+ case 'error':
566
+ const errorMsg = data.message || data.error || 'Unknown error';
567
+ addLogLine(output, `❌ ${errorMsg}`, 'error');
568
+ status.textContent = '❌ Error';
569
+ status.className = 'text-sm text-red-500 dark:text-red-400';
570
+ scrollToBottom(document.getElementById('output-container'));
571
+ break;
572
+ }
573
+ }
574
+
575
+ // Add log line to output
576
+ function addLogLine(container, text, type = 'output') {
577
+ const line = document.createElement('div');
578
+ line.className = 'log-line font-mono';
579
+
580
+ switch (type) {
581
+ case 'info':
582
+ line.className += ' text-blue-500 dark:text-blue-400';
583
+ break;
584
+ case 'success':
585
+ line.className += ' text-green-500 dark:text-green-400 font-semibold';
586
+ break;
587
+ case 'error':
588
+ line.className += ' text-red-500 dark:text-red-400 font-semibold';
589
+ break;
590
+ case 'spacer':
591
+ line.style.height = '0.5em';
592
+ line.innerHTML = '&nbsp;';
593
+ break;
594
+ default:
595
+ line.className += ' text-green-400 dark:text-green-400';
596
+ }
597
+
598
+ if (type !== 'spacer') {
599
+ line.textContent = text;
600
+ }
601
+ container.appendChild(line);
602
+ }
603
+
604
+ // Scroll to bottom helper
605
+ function scrollToBottom(element) {
606
+ if (element) {
607
+ element.scrollTop = element.scrollHeight;
608
+ }
609
+ }
610
+
611
+ // Get CSRF token
612
+ function getCookie(name) {
613
+ let cookieValue = null;
614
+ if (document.cookie && document.cookie !== '') {
615
+ const cookies = document.cookie.split(';');
616
+ for (let i = 0; i < cookies.length; i++) {
617
+ const cookie = cookies[i].trim();
618
+ if (cookie.substring(0, name.length + 1) === (name + '=')) {
619
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
620
+ break;
621
+ }
622
+ }
623
+ }
624
+ return cookieValue;
625
+ }
626
+ </script>