django-cfg 1.4.83__py3-none-any.whl → 1.4.85__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 (169) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/dashboard/__init__.py +8 -0
  3. django_cfg/apps/dashboard/apps.py +23 -0
  4. django_cfg/apps/dashboard/serializers/__init__.py +55 -0
  5. django_cfg/apps/dashboard/serializers/activity.py +38 -0
  6. django_cfg/apps/dashboard/serializers/apizones.py +26 -0
  7. django_cfg/apps/dashboard/serializers/base.py +16 -0
  8. django_cfg/apps/dashboard/serializers/charts.py +44 -0
  9. django_cfg/apps/dashboard/serializers/commands.py +26 -0
  10. django_cfg/apps/dashboard/serializers/overview.py +34 -0
  11. django_cfg/apps/dashboard/serializers/statistics.py +46 -0
  12. django_cfg/apps/dashboard/serializers/system.py +58 -0
  13. django_cfg/apps/dashboard/services/__init__.py +20 -0
  14. django_cfg/apps/dashboard/services/apizones_service.py +119 -0
  15. django_cfg/apps/dashboard/services/charts_service.py +266 -0
  16. django_cfg/apps/dashboard/services/commands_service.py +142 -0
  17. django_cfg/apps/dashboard/services/statistics_service.py +393 -0
  18. django_cfg/apps/dashboard/services/system_health_service.py +280 -0
  19. django_cfg/apps/dashboard/urls.py +42 -0
  20. django_cfg/apps/dashboard/views/__init__.py +23 -0
  21. django_cfg/apps/dashboard/views/activity_views.py +83 -0
  22. django_cfg/apps/dashboard/views/apizones_views.py +73 -0
  23. django_cfg/apps/dashboard/views/charts_views.py +159 -0
  24. django_cfg/apps/dashboard/views/commands_views.py +73 -0
  25. django_cfg/apps/dashboard/views/overview_views.py +92 -0
  26. django_cfg/apps/dashboard/views/statistics_views.py +105 -0
  27. django_cfg/apps/dashboard/views/system_views.py +73 -0
  28. django_cfg/apps/frontend/views.py +5 -0
  29. django_cfg/apps/urls.py +2 -1
  30. django_cfg/core/builders/apps_builder.py +1 -0
  31. django_cfg/modules/django_client/core/parser/openapi30.py +12 -5
  32. django_cfg/modules/django_client/core/parser/openapi31.py +12 -5
  33. django_cfg/modules/django_unfold/callbacks/main.py +7 -6
  34. django_cfg/modules/django_unfold/dashboard.py +1 -36
  35. django_cfg/modules/django_unfold/models/config.py +102 -73
  36. django_cfg/modules/django_unfold/tailwind.py +31 -79
  37. django_cfg/pyproject.toml +1 -1
  38. django_cfg/static/frontend/admin/404.html +1 -1
  39. django_cfg/static/frontend/admin/500.html +1 -1
  40. django_cfg/static/frontend/admin/_next/static/BembwiEtlu4eFl3OX7n1k/_buildManifest.js +1 -0
  41. django_cfg/static/frontend/admin/_next/static/chunks/23004-faae121bbfecc163.js +1 -0
  42. django_cfg/static/frontend/admin/_next/static/chunks/{25033.d626f78bc99bc4a1.js → 25033.ee3e206d5a2877b6.js} +2 -2
  43. django_cfg/static/frontend/admin/_next/static/chunks/{25892.964150a58f94ce06.js → 25892.5cbed319f9226fdc.js} +1 -1
  44. django_cfg/static/frontend/admin/_next/static/chunks/{2d7a934f.dfef67639279d59d.js → 2d7a934f.329c61f23af1a7ec.js} +1 -1
  45. django_cfg/static/frontend/admin/_next/static/chunks/{30649.00c679812a56aee3.js → 30649.963cfb7268b5864a.js} +1 -1
  46. django_cfg/static/frontend/admin/_next/static/chunks/{30875.784491146c38dbcb.js → 30875.82c3741757b8aa32.js} +1 -1
  47. django_cfg/static/frontend/admin/_next/static/chunks/{32163.ab0ca435b3f26c04.js → 32163.109a03a7252f1508.js} +1 -1
  48. django_cfg/static/frontend/admin/_next/static/chunks/{49978.fb8ba7ee52ffe666.js → 49978.db5a86a8eb233f35.js} +1 -1
  49. django_cfg/static/frontend/admin/_next/static/chunks/50314-3b9d15242191c8bc.js +1 -0
  50. django_cfg/static/frontend/admin/_next/static/chunks/{50319.f786248384877960.js → 50319.fd78c7f7e3f1966e.js} +1 -1
  51. django_cfg/static/frontend/admin/_next/static/chunks/{52908.b690e323d8f8efdd.js → 52908.da5b850b0bc0970c.js} +1 -1
  52. django_cfg/static/frontend/admin/_next/static/chunks/{53710.80ca863525d137db.js → 53710.7176bbee6c7b78be.js} +1 -1
  53. django_cfg/static/frontend/admin/_next/static/chunks/{57982.251fed8d58adcf53.js → 57982.2c90b33b0934522a.js} +2 -2
  54. django_cfg/static/frontend/admin/_next/static/chunks/{60181.86e18057c4caaa97.js → 60181.c94d78d10eb5da37.js} +1 -1
  55. django_cfg/static/frontend/admin/_next/static/chunks/{60374.bde0ec1249aa79c6.js → 60374.5d80cfc45439b2b0.js} +1 -1
  56. django_cfg/static/frontend/admin/_next/static/chunks/{64330.2ef79bccd7d4e363.js → 64330.41858e98c0e5173b.js} +1 -1
  57. django_cfg/static/frontend/admin/_next/static/chunks/6766.8d01e44e83070e83.js +1 -0
  58. django_cfg/static/frontend/admin/_next/static/chunks/{6884.7b1db804c88280ed.js → 6884.624d563508cf6db4.js} +1 -1
  59. django_cfg/static/frontend/admin/_next/static/chunks/{69436.9515b854cdf4b57a.js → 69436.be44021e3d7c99c7.js} +1 -1
  60. django_cfg/static/frontend/admin/_next/static/chunks/{70628.00cdd98f672e684f.js → 70628.58e8c38a66543d5e.js} +1 -1
  61. django_cfg/static/frontend/admin/_next/static/chunks/{73218.a826c2248612b37f.js → 73218.d712e7bd678e23a8.js} +1 -1
  62. django_cfg/static/frontend/admin/_next/static/chunks/{76334.64fbaa923d9ac293.js → 76334.f43f2d8b4bbf8dd6.js} +1 -1
  63. django_cfg/static/frontend/admin/_next/static/chunks/{7799.2b280f8ddf067d49.js → 7799.1575cc212bc750c7.js} +1 -1
  64. django_cfg/static/frontend/admin/_next/static/chunks/{80574.620a8a5b4eb91c25.js → 80574.92638dd7b9979664.js} +1 -1
  65. django_cfg/static/frontend/admin/_next/static/chunks/{81127.a0603c3394892d4e.js → 81127.3ead500eec887152.js} +1 -1
  66. django_cfg/static/frontend/admin/_next/static/chunks/{8383.eb6188b22c453e14.js → 8383.e25a442df26b2e26.js} +1 -1
  67. django_cfg/static/frontend/admin/_next/static/chunks/{85833.35e6ca25ac32a7d2.js → 85833.b0dead4fbcbfdd1b.js} +1 -1
  68. django_cfg/static/frontend/admin/_next/static/chunks/{95365.fc9d7653a78839d0.js → 95365.2b430045fc2e5acf.js} +1 -1
  69. django_cfg/static/frontend/admin/_next/static/chunks/{96168.eb7fdb721b9cdb00.js → 96168.b7197f890097df6e.js} +1 -1
  70. django_cfg/static/frontend/admin/_next/static/chunks/{96424.0793b94836eb13a6.js → 96424.11d76570e9a94b85.js} +1 -1
  71. django_cfg/static/frontend/admin/_next/static/chunks/pages/{404-c283223d1afd02a2.js → 404-cf71cd7b3cb005e5.js} +1 -1
  72. django_cfg/static/frontend/admin/_next/static/chunks/pages/{500-389d6d3e1f2f7fda.js → 500-ff19c7842e3df415.js} +1 -1
  73. django_cfg/static/frontend/admin/_next/static/chunks/pages/_app-f62e5528fbcbb6b3.js +272 -0
  74. django_cfg/static/frontend/admin/_next/static/chunks/pages/{_error-5291033275c26d09.js → _error-87f3fdc2aa131e77.js} +1 -1
  75. django_cfg/static/frontend/admin/_next/static/chunks/pages/index-69f737d4802cc5b7.js +1 -0
  76. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{cookies-bb5507a122775f30.js → cookies-b39c7f22c066e2c6.js} +1 -1
  77. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{privacy-f8a3d8db1a197be3.js → privacy-5aedad0cf3a4f80f.js} +1 -1
  78. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{security-aba50addd2179f8f.js → security-dbd854d0d5d483e2.js} +1 -1
  79. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{terms-4aa35cd30b5c08ad.js → terms-f3e1d2b9e5edf12f.js} +1 -1
  80. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/centrifugo-f24beb6ed3955aa8.js +1 -0
  81. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/{profile-e93a65e8e7d9022b.js → profile-b8045f993287f1a7.js} +1 -1
  82. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/ui-373fff8b42878e64.js +1 -0
  83. django_cfg/static/frontend/admin/_next/static/chunks/pages/private-fe9faa86ecdb0ce6.js +1 -0
  84. django_cfg/static/frontend/admin/_next/static/chunks/{webpack-905bba30877f6490.js → webpack-7c456a65e96eb97e.js} +1 -1
  85. django_cfg/static/frontend/admin/_next/static/css/5f9a37b6e6a72303.css +3 -0
  86. django_cfg/static/frontend/admin/auth.html +1 -1
  87. django_cfg/static/frontend/admin/index.html +1 -1
  88. django_cfg/static/frontend/admin/legal/cookies.html +1 -1
  89. django_cfg/static/frontend/admin/legal/privacy.html +1 -1
  90. django_cfg/static/frontend/admin/legal/security.html +1 -1
  91. django_cfg/static/frontend/admin/legal/terms.html +1 -1
  92. django_cfg/static/frontend/admin/private/centrifugo.html +1 -1
  93. django_cfg/static/frontend/admin/private/profile.html +1 -1
  94. django_cfg/static/frontend/admin/private/ui.html +1 -0
  95. django_cfg/static/frontend/admin/private.html +1 -1
  96. django_cfg/templates/admin/index.html +328 -62
  97. django_cfg/templates/admin/sections/commands_section.html +5 -549
  98. django_cfg/templates/admin/sections/documentation_section.html +5 -152
  99. django_cfg/templates/admin/sections/overview_section.html +5 -112
  100. django_cfg/templates/admin/sections/stats_section.html +5 -35
  101. django_cfg/templates/admin/sections/system_section.html +5 -99
  102. django_cfg/templates/admin/sections/widgets_section.html +10 -128
  103. django_cfg/templates/admin_old/index.html +80 -0
  104. django_cfg/templates/admin_old/sections/commands_section.html +549 -0
  105. django_cfg/templates/admin_old/sections/documentation_section.html +152 -0
  106. django_cfg/templates/admin_old/sections/overview_section.html +112 -0
  107. django_cfg/templates/admin_old/sections/stats_section.html +35 -0
  108. django_cfg/templates/admin_old/sections/system_section.html +99 -0
  109. django_cfg/templates/admin_old/sections/widgets_section.html +129 -0
  110. django_cfg/templates/unfold/layouts/skeleton.html +27 -0
  111. django_cfg/templatetags/django_cfg.py +53 -0
  112. {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/METADATA +1 -1
  113. {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/RECORD +160 -124
  114. django_cfg/static/frontend/admin/_next/static/chunks/6766.d62fed7cd4761148.js +0 -1
  115. django_cfg/static/frontend/admin/_next/static/chunks/pages/_app-16701a4e1bc3e6ac.js +0 -272
  116. django_cfg/static/frontend/admin/_next/static/chunks/pages/index-88751d9f44a32105.js +0 -1
  117. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/centrifugo-1c5f00c26c77a47b.js +0 -1
  118. django_cfg/static/frontend/admin/_next/static/chunks/pages/private-2f58633ddf63a5bc.js +0 -1
  119. django_cfg/static/frontend/admin/_next/static/chunks/pages/ui-0e6c0e35862789ec.js +0 -1
  120. django_cfg/static/frontend/admin/_next/static/css/806300fb98c42afb.css +0 -3
  121. django_cfg/static/frontend/admin/_next/static/ibMHm1p66p0UGKsKnDWxn/_buildManifest.js +0 -1
  122. django_cfg/static/frontend/admin/ui.html +0 -92
  123. /django_cfg/static/frontend/admin/_next/static/{ibMHm1p66p0UGKsKnDWxn → BembwiEtlu4eFl3OX7n1k}/_ssgManifest.js +0 -0
  124. /django_cfg/templates/{admin → admin_old}/components/action_grid.html +0 -0
  125. /django_cfg/templates/{admin → admin_old}/components/card.html +0 -0
  126. /django_cfg/templates/{admin → admin_old}/components/data_table.html +0 -0
  127. /django_cfg/templates/{admin → admin_old}/components/metric_card.html +0 -0
  128. /django_cfg/templates/{admin → admin_old}/components/modal.html +0 -0
  129. /django_cfg/templates/{admin → admin_old}/components/progress_bar.html +0 -0
  130. /django_cfg/templates/{admin → admin_old}/components/section_header.html +0 -0
  131. /django_cfg/templates/{admin → admin_old}/components/stat_item.html +0 -0
  132. /django_cfg/templates/{admin → admin_old}/components/stats_grid.html +0 -0
  133. /django_cfg/templates/{admin → admin_old}/components/status_badge.html +0 -0
  134. /django_cfg/templates/{admin → admin_old}/components/user_avatar.html +0 -0
  135. /django_cfg/templates/{admin → admin_old}/constance/change_list.html +0 -0
  136. /django_cfg/templates/{admin → admin_old}/constance/includes/default_value.html +0 -0
  137. /django_cfg/templates/{admin → admin_old}/constance/includes/fieldset_header.html +0 -0
  138. /django_cfg/templates/{admin → admin_old}/constance/includes/results_list.html +0 -0
  139. /django_cfg/templates/{admin → admin_old}/constance/includes/setting_row.html +0 -0
  140. /django_cfg/templates/{admin → admin_old}/constance/includes/table_headers.html +0 -0
  141. /django_cfg/templates/{admin → admin_old}/examples/component_class_example.html +0 -0
  142. /django_cfg/templates/{admin → admin_old}/import_export/change_list_export.html +0 -0
  143. /django_cfg/templates/{admin → admin_old}/import_export/change_list_import.html +0 -0
  144. /django_cfg/templates/{admin → admin_old}/import_export/change_list_import_export.html +0 -0
  145. /django_cfg/templates/{admin → admin_old}/index_new.html +0 -0
  146. /django_cfg/templates/{admin → admin_old}/layouts/base_dashboard.html +0 -0
  147. /django_cfg/templates/{admin → admin_old}/layouts/dashboard_with_tabs.html +0 -0
  148. /django_cfg/templates/{admin → admin_old}/snippets/components/activity_tracker.html +0 -0
  149. /django_cfg/templates/{admin → admin_old}/snippets/components/charts_section.html +0 -0
  150. /django_cfg/templates/{admin → admin_old}/snippets/components/django_commands.html +0 -0
  151. /django_cfg/templates/{admin → admin_old}/snippets/components/quick_actions.html +0 -0
  152. /django_cfg/templates/{admin → admin_old}/snippets/components/recent_activity_improved.html +0 -0
  153. /django_cfg/templates/{admin → admin_old}/snippets/components/recent_users_table.html +0 -0
  154. /django_cfg/templates/{admin → admin_old}/snippets/components/stats_cards.html +0 -0
  155. /django_cfg/templates/{admin → admin_old}/snippets/components/stats_tiles.html +0 -0
  156. /django_cfg/templates/{admin → admin_old}/snippets/components/system_health.html +0 -0
  157. /django_cfg/templates/{admin → admin_old}/snippets/components/system_metrics.html +0 -0
  158. /django_cfg/templates/{admin → admin_old}/snippets/components/user_permissions.html +0 -0
  159. /django_cfg/templates/{admin → admin_old}/snippets/tabs/app_stats_tab.html +0 -0
  160. /django_cfg/templates/{admin → admin_old}/snippets/tabs/commands_tab.html +0 -0
  161. /django_cfg/templates/{admin → admin_old}/snippets/tabs/documentation_tab.html +0 -0
  162. /django_cfg/templates/{admin → admin_old}/snippets/tabs/overview_tab.html +0 -0
  163. /django_cfg/templates/{admin → admin_old}/snippets/tabs/stats_tab.html +0 -0
  164. /django_cfg/templates/{admin → admin_old}/snippets/tabs/users_tab.html +0 -0
  165. /django_cfg/templates/{admin → admin_old}/snippets/tabs/widgets_tab.html +0 -0
  166. /django_cfg/templates/{admin → admin_old}/snippets/zones/zones_table.html +0 -0
  167. {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/WHEEL +0 -0
  168. {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/entry_points.txt +0 -0
  169. {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/licenses/LICENSE +0 -0
@@ -1,80 +1,346 @@
1
- {% extends 'admin/layouts/dashboard_with_tabs.html' %}
1
+ {% extends 'admin/base.html' %}
2
2
 
3
+ {% load static %}
3
4
  {% load unfold %}
5
+ {% load django_cfg %}
4
6
 
5
- {% block overview_tab %}
6
- {% if overview_section %}
7
- {{ overview_section|safe }}
8
- {% else %}
9
- {% include 'admin/snippets/tabs/overview_tab.html' %}
10
- {% endif %}
7
+ {% block extrahead %}
8
+ {{ block.super }}
9
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
+ <link rel="stylesheet" href="{% static 'admin/css/dashboard.css' %}">
11
+ <style>
12
+ #nextjs-dashboard-iframe {
13
+ width: 100%;
14
+ min-height: 600px;
15
+ height: auto;
16
+ border: none;
17
+ display: block;
18
+ visibility: hidden !important;
19
+ opacity: 0 !important;
20
+ transition: height 0.2s ease-in-out, opacity 0.3s ease-in-out;
21
+ }
22
+
23
+ #nextjs-dashboard-iframe.loaded {
24
+ visibility: visible !important;
25
+ opacity: 1 !important;
26
+ }
27
+
28
+ .iframe-container {
29
+ position: relative;
30
+ background: transparent;
31
+ }
32
+
33
+ .iframe-loading {
34
+ position: absolute;
35
+ top: 50%;
36
+ left: 50%;
37
+ transform: translate(-50%, -50%);
38
+ text-align: center;
39
+ z-index: 1;
40
+ }
41
+
42
+ .iframe-loading.hidden {
43
+ display: none;
44
+ }
45
+
46
+ .spinner {
47
+ width: 48px;
48
+ height: 48px;
49
+ border: 4px solid #e5e7eb;
50
+ border-top-color: #3b82f6;
51
+ border-radius: 50%;
52
+ animation: spin 1s linear infinite;
53
+ margin: 0 auto 1rem;
54
+ }
55
+
56
+ @keyframes spin {
57
+ to { transform: rotate(360deg); }
58
+ }
59
+ </style>
11
60
  {% endblock %}
12
61
 
13
- {% block zones_tab %}
14
- {% if zones_section %}
15
- {{ zones_section|safe }}
16
- {% else %}
17
- {% include 'admin/snippets/zones/zones_table.html' %}
18
- {% endif %}
62
+ {% block breadcrumbs %}{% endblock %}
63
+
64
+ {% block title %}
65
+ {% if subtitle %}{{ subtitle }} | {% endif %}
66
+ {{ title }} | {{ site_title|default:'Django site admin' }}
19
67
  {% endblock %}
20
68
 
21
- {% block users_tab %}
22
- {% if users_section %}
23
- {{ users_section|safe }}
24
- {% else %}
25
- {% include 'admin/snippets/tabs/users_tab.html' %}
26
- {% endif %}
69
+ {% block branding %}
70
+ {% include "unfold/helpers/site_branding.html" %}
27
71
  {% endblock %}
28
72
 
29
- {% block system_tab %}
30
- {% if system_section %}
31
- {{ system_section|safe }}
32
- {% else %}
33
- <div class="space-y-8">
34
- <h2 class="text-xl font-semibold text-font-important-light dark:text-font-important-dark mb-4">
35
- System Management
36
- </h2>
73
+ {% block content %}
74
+ <!-- Main Container -->
75
+ {% component "unfold/components/container.html" %}
76
+ {% if is_frontend_dev_mode %}
77
+ <!-- Development Mode Badge -->
78
+ <div class="bg-yellow-100 dark:bg-yellow-900 border-l-4 border-yellow-500 text-yellow-700 dark:text-yellow-300 p-4 mb-4" role="alert">
79
+ <div class="flex items-center">
80
+ <svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
81
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
82
+ </svg>
83
+ <div>
84
+ <p class="font-bold">Frontend Development Mode Active</p>
85
+ <p class="text-sm">Loading Next.js from <code class="bg-yellow-200 dark:bg-yellow-800 px-1 rounded">{% nextjs_admin_url %}</code></p>
86
+ </div>
87
+ </div>
88
+ </div>
89
+ {% endif %}
37
90
 
38
- <!-- System Health -->
39
- {% include 'admin/snippets/components/system_health.html' %}
91
+ <!-- Next.js Dashboard iframe -->
92
+ <div class="iframe-container">
93
+ <div class="iframe-loading" id="iframe-loading">
94
+ <div class="spinner"></div>
95
+ <p id="loading-text">Loading Next.js Dashboard...</p>
96
+ </div>
40
97
 
41
- <!-- System Metrics -->
42
- {% include 'admin/snippets/components/system_metrics.html' %}
98
+ <iframe
99
+ id="nextjs-dashboard-iframe"
100
+ src="{% nextjs_admin_url 'private' %}"
101
+ title="Next.js Dashboard"
102
+ sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals"
103
+ ></iframe>
104
+ </div>
43
105
 
44
- <!-- Activity Tracker -->
45
- {% include 'admin/snippets/components/activity_tracker.html' %}
106
+ <!-- Footer Section -->
107
+ <div class="text-center py-8 mt-5">
108
+ <p class="text-sm text-gray-500 dark:text-gray-400">
109
+ {% load django_cfg %}
110
+ <a href="{% lib_site_url %}" class="text-blue-600 hover:text-blue-700 font-medium">
111
+ {% lib_name %}
112
+ </a>
113
+ <span class="mx-2">•</span>
114
+ <a href="{% lib_health_url %}" class="text-blue-600 hover:text-blue-700">
115
+ System Health
116
+ </a>
117
+ </p>
46
118
  </div>
47
- {% endif %}
119
+ {% endcomponent %}
48
120
  {% endblock %}
49
121
 
50
- {% block stats_tab %}
51
- {% if stats_section %}
52
- {{ stats_section|safe }}
53
- {% else %}
54
- {% include 'admin/snippets/tabs/stats_tab.html' %}
55
- {% endif %}
56
- {% endblock %}
122
+ {% block footer %}
123
+ {{ block.super }}
124
+ <script>
125
+ (function() {
126
+ const iframe = document.getElementById('nextjs-dashboard-iframe');
127
+ const loading = document.getElementById('iframe-loading');
128
+ const loadingText = document.getElementById('loading-text');
57
129
 
58
- {% block app_stats_tab %}
59
- {% if app_stats_section %}
60
- {{ app_stats_section|safe }}
61
- {% else %}
62
- {% include 'admin/snippets/tabs/app_stats_tab.html' with stats_groups=stats_groups %}
63
- {% endif %}
64
- {% endblock %}
130
+ // Log initial state
131
+ console.log('[Parent] 🎬 Initial iframe state:', {
132
+ visibility: window.getComputedStyle(iframe).visibility,
133
+ opacity: window.getComputedStyle(iframe).opacity,
134
+ hasLoadedClass: iframe.classList.contains('loaded')
135
+ });
65
136
 
66
- {% block commands_tab %}
67
- {% if commands_section %}
68
- {{ commands_section|safe }}
69
- {% else %}
70
- {% include 'admin/snippets/tabs/commands_tab.html' %}
71
- {% endif %}
72
- {% endblock %}
137
+ // Detect iframe origin based on src
138
+ const iframeUrl = new URL(iframe.src);
139
+ const iframeOrigin = iframeUrl.origin;
140
+ const isDevMode = iframeOrigin !== window.location.origin;
141
+
142
+ // Debug logging (uncomment for debugging)
143
+ // console.log('[Parent] 🚀 Initializing iframe communication');
144
+ // console.log('[Parent] 📍 Parent origin:', window.location.origin);
145
+ // console.log('[Parent] 📍 iframe origin:', iframeOrigin);
146
+ // console.log('[Parent] 🔧 Dev mode:', isDevMode);
147
+
148
+ iframe.addEventListener('load', function() {
149
+ // console.log('[Parent] 🎬 iframe load event fired');
150
+
151
+ // Send initial data (theme + auth) to iframe after a small delay
152
+ // to ensure iframe is fully initialized
153
+ setTimeout(() => {
154
+ // console.log('[Parent] ⏱️ Sending initial data after iframe load');
155
+ sendDataToIframe();
156
+ }, 100);
157
+ });
158
+
159
+ // Hide loading after 5 seconds if iframe doesn't load
160
+ setTimeout(() => {
161
+ loading.classList.add('hidden');
162
+ }, 5000);
163
+
164
+ // Function to send theme and auth to iframe
165
+ function sendDataToIframe() {
166
+ // console.log('[Parent] 📤 sendDataToIframe() called');
167
+
168
+ if (!iframe || !iframe.contentWindow) {
169
+ console.error('[Parent] iframe or contentWindow not available');
170
+ return;
171
+ }
73
172
 
74
- {% block widgets_tab %}
75
- {% if widgets_section %}
76
- {{ widgets_section|safe }}
77
- {% else %}
78
- {% include 'admin/snippets/tabs/widgets_tab.html' %}
79
- {% endif %}
80
- {% endblock %}
173
+ const htmlElement = document.documentElement;
174
+ const isDark = htmlElement.classList.contains('dark');
175
+ // console.log('[Parent] 🎨 HTML element classes:', htmlElement.className);
176
+ // console.log('[Parent] 🎨 isDark:', isDark);
177
+
178
+ // Get adminTheme value from Alpine.js data if available
179
+ let themeMode = 'auto';
180
+ // console.log('[Parent] 🔍 Checking Alpine.js:', {
181
+ // hasAlpine: !!window.Alpine,
182
+ // hasAlpineData: !!(window.Alpine && window.Alpine.$data)
183
+ // });
184
+
185
+ if (window.Alpine && window.Alpine.$data) {
186
+ try {
187
+ const alpineData = window.Alpine.$data(htmlElement);
188
+ // console.log('[Parent] 🔍 Alpine data:', alpineData);
189
+ if (alpineData && alpineData.adminTheme) {
190
+ themeMode = alpineData.adminTheme;
191
+ // console.log('[Parent] ✅ Got adminTheme from Alpine:', themeMode);
192
+ }
193
+ } catch (e) {
194
+ console.warn('[Parent] Failed to get Alpine data:', e);
195
+ }
196
+ }
197
+
198
+ // Get JWT tokens from localStorage (Django injected them)
199
+ const authToken = localStorage.getItem('auth_token');
200
+ const refreshToken = localStorage.getItem('refresh_token');
201
+ // console.log('[Parent] 🔑 Tokens in localStorage:', {
202
+ // hasAuthToken: !!authToken,
203
+ // hasRefreshToken: !!refreshToken,
204
+ // authTokenLength: authToken ? authToken.length : 0
205
+ // });
206
+
207
+ // Send theme
208
+ const themeMessage = {
209
+ type: 'parent-theme',
210
+ data: {
211
+ theme: isDark ? 'dark' : 'light',
212
+ themeMode: themeMode
213
+ }
214
+ };
215
+ // console.log('[Parent] 📨 Sending theme message:', themeMessage);
216
+
217
+ try {
218
+ iframe.contentWindow.postMessage(themeMessage, iframeOrigin);
219
+ // console.log('[Parent] ✅ Theme message sent successfully to', iframeOrigin);
220
+ } catch (e) {
221
+ console.error('[Parent] Failed to send theme message:', e);
222
+ }
223
+
224
+ // Send auth tokens if available
225
+ if (authToken) {
226
+ const authMessage = {
227
+ type: 'parent-auth',
228
+ data: {
229
+ authToken: authToken,
230
+ refreshToken: refreshToken
231
+ }
232
+ };
233
+ // console.log('[Parent] 📨 Sending auth message:', {
234
+ // type: authMessage.type,
235
+ // hasAuthToken: !!authMessage.data.authToken,
236
+ // hasRefreshToken: !!authMessage.data.refreshToken
237
+ // });
238
+
239
+ try {
240
+ iframe.contentWindow.postMessage(authMessage, iframeOrigin);
241
+ // console.log('[Parent] ✅ Auth message sent successfully to', iframeOrigin);
242
+ } catch (e) {
243
+ console.error('[Parent] Failed to send auth message:', e);
244
+ }
245
+ }
246
+ // else {
247
+ // console.warn('[Parent] ⚠️ No auth token found, skipping auth message');
248
+ // }
249
+ }
250
+
251
+ // Watch for theme changes on HTML element
252
+ // console.log('[Parent] 👀 Setting up MutationObserver for theme changes');
253
+ const observer = new MutationObserver((mutations) => {
254
+ mutations.forEach((mutation) => {
255
+ if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
256
+ // console.log('[Parent] 🔄 HTML class changed, sending updated theme');
257
+ sendDataToIframe();
258
+ }
259
+ });
260
+ });
261
+
262
+ observer.observe(document.documentElement, {
263
+ attributes: true,
264
+ attributeFilter: ['class']
265
+ });
266
+ // console.log('[Parent] ✅ MutationObserver active');
267
+
268
+ // Listen for messages from iframe
269
+ // console.log('[Parent] 👂 Setting up message listener for iframe');
270
+ window.addEventListener('message', (event) => {
271
+ // console.log('[Parent] 📨 Message received from iframe:', {
272
+ // origin: event.origin,
273
+ // expectedOrigin: iframeOrigin,
274
+ // type: event.data?.type,
275
+ // data: event.data?.data
276
+ // });
277
+
278
+ if (event.origin !== iframeOrigin) {
279
+ // console.log('[Parent] ⚠️ Message from unexpected origin, ignoring');
280
+ return;
281
+ }
282
+
283
+ const { type, data } = event.data || {};
284
+
285
+ switch (type) {
286
+ case 'iframe-ready':
287
+ // console.log('[Parent] ✅ iframe-ready received:', data);
288
+ // Send data immediately when iframe is ready
289
+ // console.log('[Parent] 📤 Responding to iframe-ready by sending data');
290
+ sendDataToIframe();
291
+ break;
292
+
293
+ case 'iframe-auth-status':
294
+ // iframe sent auth status update
295
+ console.log('[Parent] 🔐 Auth status received:', data);
296
+ console.log('[Parent] 📊 Current iframe state BEFORE:', {
297
+ visibility: window.getComputedStyle(iframe).visibility,
298
+ opacity: window.getComputedStyle(iframe).opacity,
299
+ hasLoadedClass: iframe.classList.contains('loaded')
300
+ });
301
+
302
+ if (data?.isAuthenticated && !data?.isLoading) {
303
+ // User is authenticated, show iframe
304
+ console.log('[Parent] ✅ Adding .loaded class');
305
+ loading.classList.add('hidden');
306
+ iframe.classList.add('loaded');
307
+
308
+ setTimeout(() => {
309
+ console.log('[Parent] 📊 iframe state AFTER .loaded:', {
310
+ visibility: window.getComputedStyle(iframe).visibility,
311
+ opacity: window.getComputedStyle(iframe).opacity,
312
+ hasLoadedClass: iframe.classList.contains('loaded')
313
+ });
314
+ }, 100);
315
+ } else if (data?.isLoading) {
316
+ // Still loading
317
+ console.log('[Parent] ⏳ Auth loading...');
318
+ loadingText.textContent = 'Loading authentication...';
319
+ } else {
320
+ // Not authenticated
321
+ console.log('[Parent] ⚠️ Not authenticated');
322
+ loadingText.textContent = 'Waiting for authentication...';
323
+ }
324
+ break;
325
+ case 'iframe-resize':
326
+ // Update iframe height based on content (both increase and decrease)
327
+ if (data?.height && typeof data.height === 'number') {
328
+ // Add padding to avoid scroll bars (50px buffer for safety)
329
+ const newHeight = Math.max(600, data.height + 50); // Min 600px
330
+ iframe.style.height = newHeight + 'px';
331
+ }
332
+ break;
333
+ case 'iframe-navigation':
334
+ // console.log('[Parent] 🧭 iframe navigated to:', data.path);
335
+ break;
336
+ default:
337
+ // if (type) {
338
+ // console.log('[Parent] ℹ️ Unknown message type:', type);
339
+ // }
340
+ break;
341
+ }
342
+ });
343
+ // console.log('[Parent] ✅ Message listener active');
344
+ })();
345
+ </script>
346
+ {% endblock %}