django-cfg 1.4.110__py3-none-any.whl → 1.4.113__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.

Potentially problematic release.


This version of django-cfg might be problematic. Click here for more details.

Files changed (37) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/dashboard/serializers/__init__.py +10 -0
  3. django_cfg/apps/dashboard/serializers/crontab.py +84 -0
  4. django_cfg/apps/dashboard/serializers/overview.py +22 -11
  5. django_cfg/apps/dashboard/services/__init__.py +2 -0
  6. django_cfg/apps/dashboard/services/crontab_service.py +210 -0
  7. django_cfg/apps/dashboard/services/system_health_service.py +72 -0
  8. django_cfg/apps/dashboard/urls.py +2 -0
  9. django_cfg/apps/dashboard/views/__init__.py +2 -0
  10. django_cfg/apps/dashboard/views/crontab_views.py +72 -0
  11. django_cfg/apps/dashboard/views/overview_views.py +16 -2
  12. django_cfg/config.py +3 -4
  13. django_cfg/core/base/config_model.py +7 -0
  14. django_cfg/core/builders/apps_builder.py +4 -0
  15. django_cfg/core/generation/integration_generators/__init__.py +3 -0
  16. django_cfg/core/generation/integration_generators/crontab.py +64 -0
  17. django_cfg/core/generation/orchestrator.py +13 -0
  18. django_cfg/core/integration/display/startup.py +2 -2
  19. django_cfg/core/integration/url_integration.py +2 -2
  20. django_cfg/models/__init__.py +3 -0
  21. django_cfg/models/django/__init__.py +3 -0
  22. django_cfg/models/django/crontab.py +303 -0
  23. django_cfg/modules/django_admin/base/pydantic_admin.py +10 -0
  24. django_cfg/modules/django_admin/templates/django_admin/documentation_block.html +7 -1
  25. django_cfg/modules/django_admin/utils/html_builder.py +50 -2
  26. django_cfg/modules/django_admin/utils/markdown_renderer.py +19 -3
  27. django_cfg/modules/django_admin/utils/mermaid_plugin.py +288 -0
  28. django_cfg/pyproject.toml +2 -2
  29. django_cfg/registry/core.py +4 -0
  30. django_cfg/static/frontend/admin.zip +0 -0
  31. django_cfg/templates/admin/index.html +389 -166
  32. django_cfg/templatetags/django_cfg.py +8 -0
  33. {django_cfg-1.4.110.dist-info → django_cfg-1.4.113.dist-info}/METADATA +2 -1
  34. {django_cfg-1.4.110.dist-info → django_cfg-1.4.113.dist-info}/RECORD +37 -31
  35. {django_cfg-1.4.110.dist-info → django_cfg-1.4.113.dist-info}/WHEEL +0 -0
  36. {django_cfg-1.4.110.dist-info → django_cfg-1.4.113.dist-info}/entry_points.txt +0 -0
  37. {django_cfg-1.4.110.dist-info → django_cfg-1.4.113.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,288 @@
1
+ """
2
+ Mermaid diagram plugin for Mistune markdown parser.
3
+
4
+ Renders ```mermaid code blocks as interactive diagrams using Mermaid.js.
5
+ """
6
+
7
+ import re
8
+ from typing import Any, Dict
9
+
10
+
11
+ def mermaid_plugin(md):
12
+ """
13
+ Mistune plugin to render Mermaid diagrams.
14
+
15
+ Detects code fences with 'mermaid' language and renders them as
16
+ Mermaid diagram containers that will be processed by Mermaid.js.
17
+
18
+ Usage:
19
+ ```mermaid
20
+ graph TD
21
+ A[Start] --> B{Decision}
22
+ B -->|Yes| C[OK]
23
+ B -->|No| D[Cancel]
24
+ ```
25
+
26
+ Args:
27
+ md: Mistune markdown instance
28
+ """
29
+
30
+ def render_mermaid(text: str, **attrs: Any) -> str:
31
+ """
32
+ Render Mermaid diagram HTML.
33
+
34
+ Args:
35
+ text: Mermaid diagram code
36
+ **attrs: Additional attributes
37
+
38
+ Returns:
39
+ HTML with Mermaid container
40
+ """
41
+ # Generate unique ID for this diagram
42
+ import hashlib
43
+ diagram_id = f"mermaid-{hashlib.md5(text.encode()).hexdigest()[:8]}"
44
+
45
+ # Escape HTML special characters but preserve Mermaid syntax
46
+ escaped_text = text.strip()
47
+
48
+ # Return HTML container with Mermaid code
49
+ return f'''<div class="mermaid-container">
50
+ <div class="mermaid-wrapper">
51
+ <pre class="mermaid" id="{diagram_id}">
52
+ {escaped_text}
53
+ </pre>
54
+ </div>
55
+ </div>'''
56
+
57
+ # Override code block renderer for mermaid language
58
+ original_code = md.renderer.block_code
59
+
60
+ def patched_code(code: str, info: str = None, **attrs: Any) -> str:
61
+ """
62
+ Patched code block renderer that checks for mermaid language.
63
+
64
+ Args:
65
+ code: Code content
66
+ info: Language info
67
+ **attrs: Additional attributes
68
+
69
+ Returns:
70
+ Rendered code block (either Mermaid or normal code)
71
+ """
72
+ if info and info.strip().lower() == 'mermaid':
73
+ return render_mermaid(code, **attrs)
74
+ return original_code(code, info, **attrs)
75
+
76
+ md.renderer.block_code = patched_code
77
+
78
+ return md
79
+
80
+
81
+ def get_mermaid_styles() -> str:
82
+ """
83
+ Get CSS styles for Mermaid diagrams with Unfold semantic colors.
84
+
85
+ Returns:
86
+ CSS string for Mermaid container styling
87
+ """
88
+ return """
89
+ <style>
90
+ /* Mermaid container styles with Unfold semantic colors */
91
+ .mermaid-container {
92
+ margin: 1.5rem 0;
93
+ padding: 0;
94
+ }
95
+
96
+ .mermaid-wrapper {
97
+ border: 1px solid rgb(var(--color-base-200));
98
+ border-radius: 0.5rem;
99
+ padding: 1.5rem;
100
+ background: rgb(var(--color-base-50));
101
+ overflow-x: auto;
102
+ }
103
+
104
+ /* Dark mode styles with semantic colors */
105
+ .dark .mermaid-wrapper {
106
+ border-color: rgb(var(--color-base-700));
107
+ background: rgb(var(--color-base-900));
108
+ }
109
+
110
+ /* Mermaid diagram */
111
+ .mermaid {
112
+ display: flex;
113
+ justify-content: center;
114
+ background: transparent !important;
115
+ border: none !important;
116
+ padding: 0 !important;
117
+ margin: 0 !important;
118
+ font-family: inherit !important;
119
+ }
120
+
121
+ /* Ensure diagrams are centered */
122
+ .mermaid svg {
123
+ max-width: 100%;
124
+ height: auto;
125
+ }
126
+
127
+ /* Loading state with semantic colors */
128
+ .mermaid[data-processed="false"] {
129
+ color: rgb(var(--color-base-400));
130
+ text-align: center;
131
+ padding: 2rem;
132
+ }
133
+
134
+ .dark .mermaid[data-processed="false"] {
135
+ color: rgb(var(--color-base-500));
136
+ }
137
+
138
+ /* Error state with semantic colors */
139
+ .mermaid.error {
140
+ color: rgb(239, 68, 68);
141
+ border: 1px solid rgb(252, 165, 165);
142
+ background: rgb(254, 242, 242);
143
+ padding: 1rem;
144
+ border-radius: 0.375rem;
145
+ }
146
+
147
+ .dark .mermaid.error {
148
+ color: rgb(248, 113, 113);
149
+ border-color: rgb(153, 27, 27);
150
+ background: rgb(127, 29, 29);
151
+ }
152
+ </style>
153
+ """
154
+
155
+
156
+ def get_mermaid_script(theme: str = "default") -> str:
157
+ """
158
+ Get Mermaid.js initialization script with Unfold semantic colors.
159
+
160
+ Args:
161
+ theme: Mermaid theme ('default', 'dark', 'forest', 'neutral')
162
+
163
+ Returns:
164
+ HTML script tag with Mermaid.js and initialization
165
+ """
166
+ return f"""
167
+ <script type="module">
168
+ import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
169
+
170
+ // Helper to get CSS variable value
171
+ function getCSSVar(name) {{
172
+ const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
173
+ // Convert "R, G, B" format to "#RRGGBB"
174
+ if (value.includes(',')) {{
175
+ const [r, g, b] = value.split(',').map(x => parseInt(x.trim()));
176
+ return '#' + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');
177
+ }}
178
+ return value;
179
+ }}
180
+
181
+ // Auto-detect dark mode
182
+ const isDarkMode = document.documentElement.classList.contains('dark') ||
183
+ window.matchMedia('(prefers-color-scheme: dark)').matches;
184
+
185
+ // Get Unfold semantic colors
186
+ function getThemeColors() {{
187
+ if (isDarkMode) {{
188
+ return {{
189
+ primaryColor: '#3b82f6',
190
+ primaryTextColor: getCSSVar('--color-base-100'),
191
+ primaryBorderColor: getCSSVar('--color-base-700'),
192
+ lineColor: getCSSVar('--color-base-600'),
193
+ secondaryColor: getCSSVar('--color-base-800'),
194
+ tertiaryColor: getCSSVar('--color-base-700'),
195
+ background: getCSSVar('--color-base-900'),
196
+ mainBkg: getCSSVar('--color-base-800'),
197
+ secondBkg: getCSSVar('--color-base-700'),
198
+ border1: getCSSVar('--color-base-700'),
199
+ border2: getCSSVar('--color-base-600'),
200
+ note: getCSSVar('--color-base-800'),
201
+ noteText: getCSSVar('--color-base-200'),
202
+ noteBorder: getCSSVar('--color-base-600'),
203
+ text: getCSSVar('--color-base-200'),
204
+ critical: '#ef4444',
205
+ done: '#10b981',
206
+ active: '#3b82f6',
207
+ }};
208
+ }} else {{
209
+ return {{
210
+ primaryColor: '#2563eb',
211
+ primaryTextColor: getCSSVar('--color-base-900'),
212
+ primaryBorderColor: getCSSVar('--color-base-300'),
213
+ lineColor: getCSSVar('--color-base-400'),
214
+ secondaryColor: getCSSVar('--color-base-100'),
215
+ tertiaryColor: '#ffffff',
216
+ background: '#ffffff',
217
+ mainBkg: getCSSVar('--color-base-50'),
218
+ secondBkg: '#ffffff',
219
+ border1: getCSSVar('--color-base-300'),
220
+ border2: getCSSVar('--color-base-200'),
221
+ note: '#fef3c7',
222
+ noteText: getCSSVar('--color-base-900'),
223
+ noteBorder: '#fbbf24',
224
+ text: getCSSVar('--color-base-900'),
225
+ critical: '#dc2626',
226
+ done: '#059669',
227
+ active: '#2563eb',
228
+ }};
229
+ }}
230
+ }}
231
+
232
+ // Initialize Mermaid with Unfold semantic colors
233
+ mermaid.initialize({{
234
+ startOnLoad: true,
235
+ theme: 'base',
236
+ securityLevel: 'loose',
237
+ fontFamily: 'ui-sans-serif, system-ui, sans-serif',
238
+ themeVariables: getThemeColors()
239
+ }});
240
+
241
+ // Listen for dark mode changes and re-render
242
+ const observer = new MutationObserver((mutations) => {{
243
+ mutations.forEach((mutation) => {{
244
+ if (mutation.attributeName === 'class') {{
245
+ // Re-initialize with new theme colors
246
+ mermaid.initialize({{
247
+ startOnLoad: true,
248
+ theme: 'base',
249
+ securityLevel: 'loose',
250
+ fontFamily: 'ui-sans-serif, system-ui, sans-serif',
251
+ themeVariables: getThemeColors()
252
+ }});
253
+ // Re-render all diagrams
254
+ mermaid.run({{
255
+ querySelector: '.mermaid',
256
+ }});
257
+ }}
258
+ }});
259
+ }});
260
+
261
+ observer.observe(document.documentElement, {{
262
+ attributes: true,
263
+ attributeFilter: ['class'],
264
+ }});
265
+
266
+ // Error handling
267
+ window.addEventListener('error', (event) => {{
268
+ if (event.message && event.message.includes('mermaid')) {{
269
+ console.error('Mermaid error:', event);
270
+ const mermaidElements = document.querySelectorAll('.mermaid[data-processed="false"]');
271
+ mermaidElements.forEach(el => {{
272
+ el.classList.add('error');
273
+ el.textContent = 'Error rendering diagram. Check console for details.';
274
+ }});
275
+ }}
276
+ }});
277
+ </script>
278
+ """
279
+
280
+
281
+ def get_mermaid_resources() -> str:
282
+ """
283
+ Get complete Mermaid resources (styles + script).
284
+
285
+ Returns:
286
+ HTML string with styles and script for Mermaid support
287
+ """
288
+ return get_mermaid_styles() + get_mermaid_script()
django_cfg/pyproject.toml CHANGED
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "django-cfg"
7
- version = "1.4.110"
7
+ version = "1.4.113"
8
8
  description = "Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features."
9
9
  readme = "README.md"
10
10
  keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "nextjs-admin", "react-admin", "websocket", "centrifugo", "real-time", "typescript-generation", "ai-agents", "enterprise-django", "django-settings", "type-safe-config", "modern-django",]
11
11
  classifiers = [ "Development Status :: 4 - Beta", "Framework :: Django", "Framework :: Django :: 5.2", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Systems Administration", "Typing :: Typed",]
12
12
  requires-python = ">=3.12,<3.14"
13
- dependencies = [ "pydantic>=2.11.0,<3.0", "pydantic[email]>=2.11.0,<3.0", "PyYAML>=6.0,<7.0", "click>=8.2.0,<9.0", "questionary>=2.1.0,<3.0", "rich>=14.0.0,<15.0", "cloudflare>=4.3.0,<5.0", "loguru>=0.7.0,<1.0", "colorlog>=6.9.0,<7.0", "cachetools>=5.3.0,<7.0", "toml>=0.10.2,<0.11.0", "ngrok>=1.5.1; python_version>='3.12'", "psycopg[binary,pool]>=3.2.0,<4.0", "dj-database-url>=3.0.0,<4.0", "whitenoise>=6.8.0,<7.0", "django-cors-headers>=4.7.0,<5.0", "djangorestframework>=3.16.0,<4.0", "djangorestframework-simplejwt>=5.5.0,<6.0", "djangorestframework-simplejwt[token-blacklist]>=5.5.0,<6.0", "drf-nested-routers>=0.94.0,<1.0", "django-filter>=25.0,<26.0", "django-ratelimit>=4.1.0,<5.0.0", "drf-spectacular>=0.28.0,<1.0", "drf-spectacular-sidecar>=2025.8.0,<2026.0", "django-json-widget>=2.0.0,<3.0", "django-import-export>=4.3.0,<5.0", "django-extensions>=4.1.0,<5.0", "django-constance>=4.3.0,<5.0", "django-unfold>=0.64.0,<1.0", "django-redis>=6.0.0,<7.0", "redis>=6.4.0,<7.0", "hiredis>=2.0.0,<4.0", "rearq>=0.2.0,<1.0", "setuptools>=75.0.0; python_version>='3.13'", "pyTelegramBotAPI>=4.28.0,<5.0", "coolname>=2.2.0,<3.0", "django-admin-rangefilter>=0.13.0,<1.0", "python-json-logger>=3.3.0,<4.0", "requests>=2.32.0,<3.0", "tiktoken>=0.11.0,<1.0", "openai>=1.107.0,<2.0", "twilio>=9.8.0,<10.0", "sendgrid>=6.12.0,<7.0", "beautifulsoup4>=4.13.0,<5.0", "lxml>=6.0.0,<7.0", "pgvector>=0.4.0,<1.0", "tenacity>=9.1.2,<10.0.0", "mypy (>=1.18.2,<2.0.0)", "django-tailwind[reload] (>=4.2.0,<5.0.0)", "jinja2 (>=3.1.6,<4.0.0)", "django-axes[ipware] (>=8.0.0,<9.0.0)", "pydantic-settings (>=2.11.0,<3.0.0)", "pytz>=2025.1", "httpx>=0.28.1,<1.0", "mistune>=3.1.4,<4.0",]
13
+ dependencies = [ "pydantic>=2.11.0,<3.0", "pydantic[email]>=2.11.0,<3.0", "PyYAML>=6.0,<7.0", "click>=8.2.0,<9.0", "questionary>=2.1.0,<3.0", "rich>=14.0.0,<15.0", "cloudflare>=4.3.0,<5.0", "loguru>=0.7.0,<1.0", "colorlog>=6.9.0,<7.0", "cachetools>=5.3.0,<7.0", "toml>=0.10.2,<0.11.0", "ngrok>=1.5.1; python_version>='3.12'", "psycopg[binary,pool]>=3.2.0,<4.0", "dj-database-url>=3.0.0,<4.0", "whitenoise>=6.8.0,<7.0", "django-cors-headers>=4.7.0,<5.0", "django-crontab>=0.7.1,<1.0", "djangorestframework>=3.16.0,<4.0", "djangorestframework-simplejwt>=5.5.0,<6.0", "djangorestframework-simplejwt[token-blacklist]>=5.5.0,<6.0", "drf-nested-routers>=0.94.0,<1.0", "django-filter>=25.0,<26.0", "django-ratelimit>=4.1.0,<5.0.0", "drf-spectacular>=0.28.0,<1.0", "drf-spectacular-sidecar>=2025.8.0,<2026.0", "django-json-widget>=2.0.0,<3.0", "django-import-export>=4.3.0,<5.0", "django-extensions>=4.1.0,<5.0", "django-constance>=4.3.0,<5.0", "django-unfold>=0.64.0,<1.0", "django-redis>=6.0.0,<7.0", "redis>=6.4.0,<7.0", "hiredis>=2.0.0,<4.0", "rearq>=0.2.0,<1.0", "setuptools>=75.0.0; python_version>='3.13'", "pyTelegramBotAPI>=4.28.0,<5.0", "coolname>=2.2.0,<3.0", "django-admin-rangefilter>=0.13.0,<1.0", "python-json-logger>=3.3.0,<4.0", "requests>=2.32.0,<3.0", "tiktoken>=0.11.0,<1.0", "openai>=1.107.0,<2.0", "twilio>=9.8.0,<10.0", "sendgrid>=6.12.0,<7.0", "beautifulsoup4>=4.13.0,<5.0", "lxml>=6.0.0,<7.0", "pgvector>=0.4.0,<1.0", "tenacity>=9.1.2,<10.0.0", "mypy (>=1.18.2,<2.0.0)", "django-tailwind[reload] (>=4.2.0,<5.0.0)", "jinja2 (>=3.1.6,<4.0.0)", "django-axes[ipware] (>=8.0.0,<9.0.0)", "pydantic-settings (>=2.11.0,<3.0.0)", "pytz>=2025.1", "httpx>=0.28.1,<1.0", "mistune>=3.1.4,<4.0",]
14
14
  [[project.authors]]
15
15
  name = "Django-CFG Team"
16
16
  email = "info@djangocfg.com"
@@ -38,6 +38,10 @@ CORE_REGISTRY = {
38
38
  # Security - Django Crypto Fields
39
39
  "CryptoFieldsConfig": ("django_cfg.models.django.crypto_fields", "CryptoFieldsConfig"),
40
40
 
41
+ # Scheduling - Django Crontab
42
+ "CrontabConfig": ("django_cfg.models.django.crontab", "CrontabConfig"),
43
+ "CrontabJobConfig": ("django_cfg.models.django.crontab", "CrontabJobConfig"),
44
+
41
45
  # Limits models
42
46
  "LimitsConfig": ("django_cfg.models.api.limits", "LimitsConfig"),
43
47
 
Binary file