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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/dashboard/__init__.py +8 -0
- django_cfg/apps/dashboard/apps.py +23 -0
- django_cfg/apps/dashboard/serializers/__init__.py +55 -0
- django_cfg/apps/dashboard/serializers/activity.py +38 -0
- django_cfg/apps/dashboard/serializers/apizones.py +26 -0
- django_cfg/apps/dashboard/serializers/base.py +16 -0
- django_cfg/apps/dashboard/serializers/charts.py +44 -0
- django_cfg/apps/dashboard/serializers/commands.py +26 -0
- django_cfg/apps/dashboard/serializers/overview.py +34 -0
- django_cfg/apps/dashboard/serializers/statistics.py +46 -0
- django_cfg/apps/dashboard/serializers/system.py +58 -0
- django_cfg/apps/dashboard/services/__init__.py +20 -0
- django_cfg/apps/dashboard/services/apizones_service.py +119 -0
- django_cfg/apps/dashboard/services/charts_service.py +266 -0
- django_cfg/apps/dashboard/services/commands_service.py +142 -0
- django_cfg/apps/dashboard/services/statistics_service.py +393 -0
- django_cfg/apps/dashboard/services/system_health_service.py +280 -0
- django_cfg/apps/dashboard/urls.py +42 -0
- django_cfg/apps/dashboard/views/__init__.py +23 -0
- django_cfg/apps/dashboard/views/activity_views.py +83 -0
- django_cfg/apps/dashboard/views/apizones_views.py +73 -0
- django_cfg/apps/dashboard/views/charts_views.py +159 -0
- django_cfg/apps/dashboard/views/commands_views.py +73 -0
- django_cfg/apps/dashboard/views/overview_views.py +92 -0
- django_cfg/apps/dashboard/views/statistics_views.py +105 -0
- django_cfg/apps/dashboard/views/system_views.py +73 -0
- django_cfg/apps/frontend/views.py +5 -0
- django_cfg/apps/urls.py +2 -1
- django_cfg/core/builders/apps_builder.py +1 -0
- django_cfg/modules/django_client/core/parser/openapi30.py +12 -5
- django_cfg/modules/django_client/core/parser/openapi31.py +12 -5
- django_cfg/modules/django_unfold/callbacks/main.py +7 -6
- django_cfg/modules/django_unfold/dashboard.py +1 -36
- django_cfg/modules/django_unfold/models/config.py +102 -73
- django_cfg/modules/django_unfold/tailwind.py +31 -79
- django_cfg/pyproject.toml +1 -1
- django_cfg/static/frontend/admin/404.html +1 -1
- django_cfg/static/frontend/admin/500.html +1 -1
- django_cfg/static/frontend/admin/_next/static/BembwiEtlu4eFl3OX7n1k/_buildManifest.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/23004-faae121bbfecc163.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/{25033.d626f78bc99bc4a1.js → 25033.ee3e206d5a2877b6.js} +2 -2
- django_cfg/static/frontend/admin/_next/static/chunks/{25892.964150a58f94ce06.js → 25892.5cbed319f9226fdc.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{2d7a934f.dfef67639279d59d.js → 2d7a934f.329c61f23af1a7ec.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{30649.00c679812a56aee3.js → 30649.963cfb7268b5864a.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{30875.784491146c38dbcb.js → 30875.82c3741757b8aa32.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{32163.ab0ca435b3f26c04.js → 32163.109a03a7252f1508.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{49978.fb8ba7ee52ffe666.js → 49978.db5a86a8eb233f35.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/50314-3b9d15242191c8bc.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/{50319.f786248384877960.js → 50319.fd78c7f7e3f1966e.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{52908.b690e323d8f8efdd.js → 52908.da5b850b0bc0970c.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{53710.80ca863525d137db.js → 53710.7176bbee6c7b78be.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{57982.251fed8d58adcf53.js → 57982.2c90b33b0934522a.js} +2 -2
- django_cfg/static/frontend/admin/_next/static/chunks/{60181.86e18057c4caaa97.js → 60181.c94d78d10eb5da37.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{60374.bde0ec1249aa79c6.js → 60374.5d80cfc45439b2b0.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{64330.2ef79bccd7d4e363.js → 64330.41858e98c0e5173b.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/6766.8d01e44e83070e83.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/{6884.7b1db804c88280ed.js → 6884.624d563508cf6db4.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{69436.9515b854cdf4b57a.js → 69436.be44021e3d7c99c7.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{70628.00cdd98f672e684f.js → 70628.58e8c38a66543d5e.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{73218.a826c2248612b37f.js → 73218.d712e7bd678e23a8.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{76334.64fbaa923d9ac293.js → 76334.f43f2d8b4bbf8dd6.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{7799.2b280f8ddf067d49.js → 7799.1575cc212bc750c7.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{80574.620a8a5b4eb91c25.js → 80574.92638dd7b9979664.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{81127.a0603c3394892d4e.js → 81127.3ead500eec887152.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{8383.eb6188b22c453e14.js → 8383.e25a442df26b2e26.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{85833.35e6ca25ac32a7d2.js → 85833.b0dead4fbcbfdd1b.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{95365.fc9d7653a78839d0.js → 95365.2b430045fc2e5acf.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{96168.eb7fdb721b9cdb00.js → 96168.b7197f890097df6e.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/{96424.0793b94836eb13a6.js → 96424.11d76570e9a94b85.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/{404-c283223d1afd02a2.js → 404-cf71cd7b3cb005e5.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/{500-389d6d3e1f2f7fda.js → 500-ff19c7842e3df415.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/_app-f62e5528fbcbb6b3.js +272 -0
- django_cfg/static/frontend/admin/_next/static/chunks/pages/{_error-5291033275c26d09.js → _error-87f3fdc2aa131e77.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/index-69f737d4802cc5b7.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{cookies-bb5507a122775f30.js → cookies-b39c7f22c066e2c6.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{privacy-f8a3d8db1a197be3.js → privacy-5aedad0cf3a4f80f.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{security-aba50addd2179f8f.js → security-dbd854d0d5d483e2.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{terms-4aa35cd30b5c08ad.js → terms-f3e1d2b9e5edf12f.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/private/centrifugo-f24beb6ed3955aa8.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/pages/private/{profile-e93a65e8e7d9022b.js → profile-b8045f993287f1a7.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/private/ui-373fff8b42878e64.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/pages/private-fe9faa86ecdb0ce6.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/{webpack-905bba30877f6490.js → webpack-7c456a65e96eb97e.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/css/5f9a37b6e6a72303.css +3 -0
- django_cfg/static/frontend/admin/auth.html +1 -1
- django_cfg/static/frontend/admin/index.html +1 -1
- django_cfg/static/frontend/admin/legal/cookies.html +1 -1
- django_cfg/static/frontend/admin/legal/privacy.html +1 -1
- django_cfg/static/frontend/admin/legal/security.html +1 -1
- django_cfg/static/frontend/admin/legal/terms.html +1 -1
- django_cfg/static/frontend/admin/private/centrifugo.html +1 -1
- django_cfg/static/frontend/admin/private/profile.html +1 -1
- django_cfg/static/frontend/admin/private/ui.html +1 -0
- django_cfg/static/frontend/admin/private.html +1 -1
- django_cfg/templates/admin/index.html +328 -62
- django_cfg/templates/admin/sections/commands_section.html +5 -549
- django_cfg/templates/admin/sections/documentation_section.html +5 -152
- django_cfg/templates/admin/sections/overview_section.html +5 -112
- django_cfg/templates/admin/sections/stats_section.html +5 -35
- django_cfg/templates/admin/sections/system_section.html +5 -99
- django_cfg/templates/admin/sections/widgets_section.html +10 -128
- django_cfg/templates/admin_old/index.html +80 -0
- django_cfg/templates/admin_old/sections/commands_section.html +549 -0
- django_cfg/templates/admin_old/sections/documentation_section.html +152 -0
- django_cfg/templates/admin_old/sections/overview_section.html +112 -0
- django_cfg/templates/admin_old/sections/stats_section.html +35 -0
- django_cfg/templates/admin_old/sections/system_section.html +99 -0
- django_cfg/templates/admin_old/sections/widgets_section.html +129 -0
- django_cfg/templates/unfold/layouts/skeleton.html +27 -0
- django_cfg/templatetags/django_cfg.py +53 -0
- {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/METADATA +1 -1
- {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/RECORD +160 -124
- django_cfg/static/frontend/admin/_next/static/chunks/6766.d62fed7cd4761148.js +0 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/_app-16701a4e1bc3e6ac.js +0 -272
- django_cfg/static/frontend/admin/_next/static/chunks/pages/index-88751d9f44a32105.js +0 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/private/centrifugo-1c5f00c26c77a47b.js +0 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/private-2f58633ddf63a5bc.js +0 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/ui-0e6c0e35862789ec.js +0 -1
- django_cfg/static/frontend/admin/_next/static/css/806300fb98c42afb.css +0 -3
- django_cfg/static/frontend/admin/_next/static/ibMHm1p66p0UGKsKnDWxn/_buildManifest.js +0 -1
- django_cfg/static/frontend/admin/ui.html +0 -92
- /django_cfg/static/frontend/admin/_next/static/{ibMHm1p66p0UGKsKnDWxn → BembwiEtlu4eFl3OX7n1k}/_ssgManifest.js +0 -0
- /django_cfg/templates/{admin → admin_old}/components/action_grid.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/card.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/data_table.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/metric_card.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/modal.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/progress_bar.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/section_header.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/stat_item.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/stats_grid.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/status_badge.html +0 -0
- /django_cfg/templates/{admin → admin_old}/components/user_avatar.html +0 -0
- /django_cfg/templates/{admin → admin_old}/constance/change_list.html +0 -0
- /django_cfg/templates/{admin → admin_old}/constance/includes/default_value.html +0 -0
- /django_cfg/templates/{admin → admin_old}/constance/includes/fieldset_header.html +0 -0
- /django_cfg/templates/{admin → admin_old}/constance/includes/results_list.html +0 -0
- /django_cfg/templates/{admin → admin_old}/constance/includes/setting_row.html +0 -0
- /django_cfg/templates/{admin → admin_old}/constance/includes/table_headers.html +0 -0
- /django_cfg/templates/{admin → admin_old}/examples/component_class_example.html +0 -0
- /django_cfg/templates/{admin → admin_old}/import_export/change_list_export.html +0 -0
- /django_cfg/templates/{admin → admin_old}/import_export/change_list_import.html +0 -0
- /django_cfg/templates/{admin → admin_old}/import_export/change_list_import_export.html +0 -0
- /django_cfg/templates/{admin → admin_old}/index_new.html +0 -0
- /django_cfg/templates/{admin → admin_old}/layouts/base_dashboard.html +0 -0
- /django_cfg/templates/{admin → admin_old}/layouts/dashboard_with_tabs.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/activity_tracker.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/charts_section.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/django_commands.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/quick_actions.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/recent_activity_improved.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/recent_users_table.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/stats_cards.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/stats_tiles.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/system_health.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/system_metrics.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/components/user_permissions.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/tabs/app_stats_tab.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/tabs/commands_tab.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/tabs/documentation_tab.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/tabs/overview_tab.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/tabs/stats_tab.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/tabs/users_tab.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/tabs/widgets_tab.html +0 -0
- /django_cfg/templates/{admin → admin_old}/snippets/zones/zones_table.html +0 -0
- {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.83.dist-info → django_cfg-1.4.85.dist-info}/entry_points.txt +0 -0
- {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/
|
|
1
|
+
{% extends 'admin/base.html' %}
|
|
2
2
|
|
|
3
|
+
{% load static %}
|
|
3
4
|
{% load unfold %}
|
|
5
|
+
{% load django_cfg %}
|
|
4
6
|
|
|
5
|
-
{% block
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
{%
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{%
|
|
17
|
-
|
|
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
|
|
22
|
-
{%
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
{%
|
|
119
|
+
{% endcomponent %}
|
|
48
120
|
{% endblock %}
|
|
49
121
|
|
|
50
|
-
{% block
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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 %}
|