django-cfg 1.4.88__py3-none-any.whl → 1.4.89__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/centrifugo/views/__init__.py +0 -2
- django_cfg/apps/dashboard/services/__init__.py +2 -0
- django_cfg/apps/dashboard/services/overview_service.py +205 -0
- django_cfg/apps/frontend/test_routing.py +134 -0
- django_cfg/apps/frontend/views.py +69 -28
- django_cfg/apps/urls.py +0 -1
- django_cfg/core/builders/apps_builder.py +0 -58
- django_cfg/modules/django_unfold/__init__.py +5 -24
- django_cfg/modules/django_unfold/models/__init__.py +0 -23
- django_cfg/modules/django_unfold/models/config.py +11 -65
- django_cfg/modules/django_unfold/{dashboard.py → navigation.py} +21 -152
- django_cfg/modules/django_unfold/tailwind.py +2 -4
- django_cfg/pyproject.toml +1 -1
- django_cfg/registry/third_party.py +0 -9
- django_cfg/routing/callbacks.py +1 -43
- django_cfg/static/frontend/admin/404/index.html +1 -1
- django_cfg/static/frontend/admin/404.html +1 -1
- django_cfg/static/frontend/admin/500/index.html +1 -1
- django_cfg/static/frontend/admin/_next/static/{D_d9HRw5Yn7BRHAX5q89_ → 0sN9ktsgXH48ygtGSrhfu}/_buildManifest.js +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/50314-9443faa6df24aebf.js +1 -0
- django_cfg/static/frontend/admin/_next/static/chunks/pages/{_app-1c0fff0f59a6d683.js → _app-c7dcd3aa616fab68.js} +1 -1
- django_cfg/static/frontend/admin/_next/static/chunks/pages/private/{centrifugo-44a8313fa040e9ad.js → centrifugo-f9ecbc3ae0052a03.js} +1 -1
- django_cfg/static/frontend/admin/auth/index.html +1 -1
- django_cfg/static/frontend/admin/index.html +1 -1
- django_cfg/static/frontend/admin/legal/cookies/index.html +1 -1
- django_cfg/static/frontend/admin/legal/privacy/index.html +1 -1
- django_cfg/static/frontend/admin/legal/security/index.html +1 -1
- django_cfg/static/frontend/admin/legal/terms/index.html +1 -1
- django_cfg/static/frontend/admin/private/centrifugo/index.html +1 -1
- django_cfg/static/frontend/admin/private/index.html +1 -1
- django_cfg/static/frontend/admin/private/profile/index.html +1 -1
- django_cfg/static/frontend/admin/private/ui/index.html +2 -2
- {django_cfg-1.4.88.dist-info → django_cfg-1.4.89.dist-info}/METADATA +1 -1
- {django_cfg-1.4.88.dist-info → django_cfg-1.4.89.dist-info}/RECORD +39 -143
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +0 -260
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +0 -313
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +0 -803
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +0 -341
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +0 -432
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +0 -33
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +0 -210
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +0 -46
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +0 -123
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +0 -45
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +0 -84
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/stat_cards.html +0 -53
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +0 -91
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/tab_navigation.html +0 -29
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +0 -415
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +0 -61
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +0 -58
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +0 -48
- django_cfg/apps/centrifugo/templatetags/__init__.py +0 -1
- django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +0 -81
- django_cfg/apps/centrifugo/urls_admin.py +0 -20
- django_cfg/apps/centrifugo/views/dashboard.py +0 -28
- django_cfg/modules/django_dashboard/__init__.py +0 -23
- django_cfg/modules/django_dashboard/components.py +0 -312
- django_cfg/modules/django_dashboard/debug.py +0 -174
- django_cfg/modules/django_dashboard/management/__init__.py +0 -0
- django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
- django_cfg/modules/django_dashboard/management/commands/debug_dashboard.py +0 -109
- django_cfg/modules/django_dashboard/sections/__init__.py +0 -1
- django_cfg/modules/django_dashboard/sections/base.py +0 -129
- django_cfg/modules/django_dashboard/sections/commands.py +0 -33
- django_cfg/modules/django_dashboard/sections/documentation.py +0 -393
- django_cfg/modules/django_dashboard/sections/overview.py +0 -398
- django_cfg/modules/django_dashboard/sections/stats.py +0 -48
- django_cfg/modules/django_dashboard/sections/system.py +0 -74
- django_cfg/modules/django_dashboard/sections/widgets.py +0 -222
- django_cfg/modules/django_unfold/callbacks/__init__.py +0 -9
- django_cfg/modules/django_unfold/callbacks/actions.py +0 -51
- django_cfg/modules/django_unfold/callbacks/apizones.py +0 -122
- django_cfg/modules/django_unfold/callbacks/base.py +0 -290
- django_cfg/modules/django_unfold/callbacks/charts.py +0 -223
- django_cfg/modules/django_unfold/callbacks/commands.py +0 -40
- django_cfg/modules/django_unfold/callbacks/main.py +0 -322
- django_cfg/modules/django_unfold/callbacks/statistics.py +0 -240
- django_cfg/modules/django_unfold/callbacks/system.py +0 -180
- django_cfg/modules/django_unfold/callbacks/users.py +0 -65
- django_cfg/modules/django_unfold/models/dashboard.py +0 -207
- django_cfg/modules/django_unfold/models/tabs.py +0 -26
- django_cfg/modules/django_unfold/models.py +0 -98
- django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +0 -102
- django_cfg/static/frontend/admin/_next/static/chunks/50314-5ec79b293c2283dd.js +0 -1
- django_cfg/templates/admin/sections/commands_section.html +0 -5
- django_cfg/templates/admin/sections/documentation_section.html +0 -5
- django_cfg/templates/admin/sections/overview_section.html +0 -5
- django_cfg/templates/admin/sections/stats_section.html +0 -5
- django_cfg/templates/admin/sections/system_section.html +0 -5
- django_cfg/templates/admin/sections/widgets_section.html +0 -11
- django_cfg/templates/admin_old/components/action_grid.html +0 -49
- django_cfg/templates/admin_old/components/card.html +0 -50
- django_cfg/templates/admin_old/components/data_table.html +0 -67
- django_cfg/templates/admin_old/components/metric_card.html +0 -39
- django_cfg/templates/admin_old/components/modal.html +0 -58
- django_cfg/templates/admin_old/components/progress_bar.html +0 -20
- django_cfg/templates/admin_old/components/section_header.html +0 -26
- django_cfg/templates/admin_old/components/stat_item.html +0 -32
- django_cfg/templates/admin_old/components/stats_grid.html +0 -72
- django_cfg/templates/admin_old/components/status_badge.html +0 -28
- django_cfg/templates/admin_old/components/user_avatar.html +0 -27
- django_cfg/templates/admin_old/constance/change_list.html +0 -74
- django_cfg/templates/admin_old/constance/includes/default_value.html +0 -24
- django_cfg/templates/admin_old/constance/includes/fieldset_header.html +0 -15
- django_cfg/templates/admin_old/constance/includes/results_list.html +0 -16
- django_cfg/templates/admin_old/constance/includes/setting_row.html +0 -50
- django_cfg/templates/admin_old/constance/includes/table_headers.html +0 -10
- django_cfg/templates/admin_old/examples/component_class_example.html +0 -156
- django_cfg/templates/admin_old/import_export/change_list_export.html +0 -24
- django_cfg/templates/admin_old/import_export/change_list_import.html +0 -24
- django_cfg/templates/admin_old/import_export/change_list_import_export.html +0 -34
- django_cfg/templates/admin_old/index.html +0 -80
- django_cfg/templates/admin_old/index_new.html +0 -119
- django_cfg/templates/admin_old/layouts/base_dashboard.html +0 -62
- django_cfg/templates/admin_old/layouts/dashboard_with_tabs.html +0 -176
- django_cfg/templates/admin_old/sections/commands_section.html +0 -549
- django_cfg/templates/admin_old/sections/documentation_section.html +0 -152
- django_cfg/templates/admin_old/sections/overview_section.html +0 -112
- django_cfg/templates/admin_old/sections/stats_section.html +0 -35
- django_cfg/templates/admin_old/sections/system_section.html +0 -99
- django_cfg/templates/admin_old/sections/widgets_section.html +0 -129
- django_cfg/templates/admin_old/snippets/components/activity_tracker.html +0 -70
- django_cfg/templates/admin_old/snippets/components/charts_section.html +0 -113
- django_cfg/templates/admin_old/snippets/components/django_commands.html +0 -270
- django_cfg/templates/admin_old/snippets/components/quick_actions.html +0 -66
- django_cfg/templates/admin_old/snippets/components/recent_activity_improved.html +0 -25
- django_cfg/templates/admin_old/snippets/components/recent_users_table.html +0 -102
- django_cfg/templates/admin_old/snippets/components/stats_cards.html +0 -4
- django_cfg/templates/admin_old/snippets/components/stats_tiles.html +0 -92
- django_cfg/templates/admin_old/snippets/components/system_health.html +0 -22
- django_cfg/templates/admin_old/snippets/components/system_metrics.html +0 -199
- django_cfg/templates/admin_old/snippets/components/user_permissions.html +0 -57
- django_cfg/templates/admin_old/snippets/tabs/app_stats_tab.html +0 -201
- django_cfg/templates/admin_old/snippets/tabs/commands_tab.html +0 -114
- django_cfg/templates/admin_old/snippets/tabs/documentation_tab.html +0 -42
- django_cfg/templates/admin_old/snippets/tabs/overview_tab.html +0 -116
- django_cfg/templates/admin_old/snippets/tabs/stats_tab.html +0 -89
- django_cfg/templates/admin_old/snippets/tabs/users_tab.html +0 -51
- django_cfg/templates/admin_old/snippets/tabs/widgets_tab.html +0 -38
- django_cfg/templates/admin_old/snippets/zones/zones_table.html +0 -176
- /django_cfg/static/frontend/admin/_next/static/{D_d9HRw5Yn7BRHAX5q89_ → 0sN9ktsgXH48ygtGSrhfu}/_ssgManifest.js +0 -0
- {django_cfg-1.4.88.dist-info → django_cfg-1.4.89.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.88.dist-info → django_cfg-1.4.89.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.88.dist-info → django_cfg-1.4.89.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Charts data callbacks.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import logging
|
|
6
|
-
from datetime import timedelta
|
|
7
|
-
from typing import Any, Dict, List
|
|
8
|
-
|
|
9
|
-
from django.contrib.auth import get_user_model
|
|
10
|
-
from django.db.models import Count
|
|
11
|
-
from django.utils import timezone
|
|
12
|
-
|
|
13
|
-
from ..models.dashboard import ChartData, ChartDataset
|
|
14
|
-
|
|
15
|
-
logger = logging.getLogger(__name__)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ChartsCallbacks:
|
|
19
|
-
"""Charts data callbacks."""
|
|
20
|
-
|
|
21
|
-
def _get_user_model(self):
|
|
22
|
-
"""Get the user model safely."""
|
|
23
|
-
return get_user_model()
|
|
24
|
-
|
|
25
|
-
def _get_empty_chart_data(self, label: str) -> Dict[str, Any]:
|
|
26
|
-
"""Get empty chart data structure."""
|
|
27
|
-
return ChartData(
|
|
28
|
-
labels=["No Data"],
|
|
29
|
-
datasets=[
|
|
30
|
-
ChartDataset(
|
|
31
|
-
label=label,
|
|
32
|
-
data=[0],
|
|
33
|
-
backgroundColor="rgba(156, 163, 175, 0.1)",
|
|
34
|
-
borderColor="rgb(156, 163, 175)",
|
|
35
|
-
tension=0.4
|
|
36
|
-
)
|
|
37
|
-
]
|
|
38
|
-
).model_dump()
|
|
39
|
-
|
|
40
|
-
def get_user_registration_chart_data(self) -> Dict[str, Any]:
|
|
41
|
-
"""Get user registration chart data."""
|
|
42
|
-
try:
|
|
43
|
-
# Avoid database access during app initialization
|
|
44
|
-
from django.apps import apps
|
|
45
|
-
if not apps.ready:
|
|
46
|
-
return self._get_empty_chart_data("New Users")
|
|
47
|
-
|
|
48
|
-
User = self._get_user_model()
|
|
49
|
-
|
|
50
|
-
# Get last 7 days of registration data
|
|
51
|
-
end_date = timezone.now().date()
|
|
52
|
-
start_date = end_date - timedelta(days=6)
|
|
53
|
-
|
|
54
|
-
# Generate date range
|
|
55
|
-
date_range = []
|
|
56
|
-
current_date = start_date
|
|
57
|
-
while current_date <= end_date:
|
|
58
|
-
date_range.append(current_date)
|
|
59
|
-
current_date += timedelta(days=1)
|
|
60
|
-
|
|
61
|
-
# Get registration counts by date
|
|
62
|
-
registration_data = (
|
|
63
|
-
User.objects.filter(date_joined__date__gte=start_date)
|
|
64
|
-
.extra({'date': "date(date_joined)"})
|
|
65
|
-
.values('date')
|
|
66
|
-
.annotate(count=Count('id'))
|
|
67
|
-
.order_by('date')
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
# Create data dictionary for easy lookup
|
|
71
|
-
data_dict = {item['date']: item['count'] for item in registration_data}
|
|
72
|
-
|
|
73
|
-
# Build chart data
|
|
74
|
-
labels = [date.strftime("%m/%d") for date in date_range]
|
|
75
|
-
data_points = [data_dict.get(date, 0) for date in date_range]
|
|
76
|
-
|
|
77
|
-
chart_data = ChartData(
|
|
78
|
-
labels=labels,
|
|
79
|
-
datasets=[
|
|
80
|
-
ChartDataset(
|
|
81
|
-
label="New Users",
|
|
82
|
-
data=data_points,
|
|
83
|
-
backgroundColor="rgba(59, 130, 246, 0.1)",
|
|
84
|
-
borderColor="rgb(59, 130, 246)",
|
|
85
|
-
tension=0.4
|
|
86
|
-
)
|
|
87
|
-
]
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
return chart_data.model_dump()
|
|
91
|
-
|
|
92
|
-
except Exception as e:
|
|
93
|
-
logger.error(f"Error getting user registration chart data: {e}")
|
|
94
|
-
return self._get_empty_chart_data("New Users")
|
|
95
|
-
|
|
96
|
-
def get_user_activity_chart_data(self) -> Dict[str, Any]:
|
|
97
|
-
"""Get user activity chart data."""
|
|
98
|
-
try:
|
|
99
|
-
# Avoid database access during app initialization
|
|
100
|
-
from django.apps import apps
|
|
101
|
-
if not apps.ready:
|
|
102
|
-
return self._get_empty_chart_data("Active Users")
|
|
103
|
-
|
|
104
|
-
User = self._get_user_model()
|
|
105
|
-
|
|
106
|
-
# Get activity data for last 7 days
|
|
107
|
-
end_date = timezone.now().date()
|
|
108
|
-
start_date = end_date - timedelta(days=6)
|
|
109
|
-
|
|
110
|
-
# Generate date range
|
|
111
|
-
date_range = []
|
|
112
|
-
current_date = start_date
|
|
113
|
-
while current_date <= end_date:
|
|
114
|
-
date_range.append(current_date)
|
|
115
|
-
current_date += timedelta(days=1)
|
|
116
|
-
|
|
117
|
-
# Get login activity (users who logged in each day)
|
|
118
|
-
activity_data = (
|
|
119
|
-
User.objects.filter(last_login__date__gte=start_date, last_login__isnull=False)
|
|
120
|
-
.extra({'date': "date(last_login)"})
|
|
121
|
-
.values('date')
|
|
122
|
-
.annotate(count=Count('id'))
|
|
123
|
-
.order_by('date')
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
# Create data dictionary for easy lookup
|
|
127
|
-
data_dict = {item['date']: item['count'] for item in activity_data}
|
|
128
|
-
|
|
129
|
-
# Build chart data
|
|
130
|
-
labels = [date.strftime("%m/%d") for date in date_range]
|
|
131
|
-
data_points = [data_dict.get(date, 0) for date in date_range]
|
|
132
|
-
|
|
133
|
-
chart_data = ChartData(
|
|
134
|
-
labels=labels,
|
|
135
|
-
datasets=[
|
|
136
|
-
ChartDataset(
|
|
137
|
-
label="Active Users",
|
|
138
|
-
data=data_points,
|
|
139
|
-
backgroundColor="rgba(34, 197, 94, 0.1)",
|
|
140
|
-
borderColor="rgb(34, 197, 94)",
|
|
141
|
-
tension=0.4
|
|
142
|
-
)
|
|
143
|
-
]
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
return chart_data.model_dump()
|
|
147
|
-
|
|
148
|
-
except Exception as e:
|
|
149
|
-
logger.error(f"Error getting user activity chart data: {e}")
|
|
150
|
-
return self._get_empty_chart_data("Active Users")
|
|
151
|
-
|
|
152
|
-
def get_activity_tracker_data(self) -> List[Dict[str, str]]:
|
|
153
|
-
"""Get activity tracker data for the last 52 weeks (GitHub-style)."""
|
|
154
|
-
try:
|
|
155
|
-
# Avoid database access during app initialization
|
|
156
|
-
from django.apps import apps
|
|
157
|
-
if not apps.ready:
|
|
158
|
-
return self._get_empty_tracker_data()
|
|
159
|
-
|
|
160
|
-
User = self._get_user_model()
|
|
161
|
-
|
|
162
|
-
# Get data for last 52 weeks (365 days)
|
|
163
|
-
end_date = timezone.now().date()
|
|
164
|
-
start_date = end_date - timedelta(days=364) # 52 weeks * 7 days - 1
|
|
165
|
-
|
|
166
|
-
# Get activity data by date
|
|
167
|
-
activity_data = (
|
|
168
|
-
User.objects.filter(last_login__date__gte=start_date, last_login__isnull=False)
|
|
169
|
-
.extra({'date': "date(last_login)"})
|
|
170
|
-
.values('date')
|
|
171
|
-
.annotate(count=Count('id'))
|
|
172
|
-
.order_by('date')
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
# Create data dictionary for easy lookup
|
|
176
|
-
data_dict = {item['date']: item['count'] for item in activity_data}
|
|
177
|
-
|
|
178
|
-
# Generate tracker data for each day
|
|
179
|
-
tracker_data = []
|
|
180
|
-
current_date = start_date
|
|
181
|
-
|
|
182
|
-
while current_date <= end_date:
|
|
183
|
-
activity_count = data_dict.get(current_date, 0)
|
|
184
|
-
|
|
185
|
-
# Determine color based on activity level
|
|
186
|
-
if activity_count == 0:
|
|
187
|
-
color = "bg-base-200 dark:bg-base-700"
|
|
188
|
-
level = "No activity"
|
|
189
|
-
elif activity_count <= 2:
|
|
190
|
-
color = "bg-green-200 dark:bg-green-800"
|
|
191
|
-
level = "Low activity"
|
|
192
|
-
elif activity_count <= 5:
|
|
193
|
-
color = "bg-green-400 dark:bg-green-600"
|
|
194
|
-
level = "Medium activity"
|
|
195
|
-
elif activity_count <= 10:
|
|
196
|
-
color = "bg-green-600 dark:bg-green-500"
|
|
197
|
-
level = "High activity"
|
|
198
|
-
else:
|
|
199
|
-
color = "bg-green-800 dark:bg-green-400"
|
|
200
|
-
level = "Very high activity"
|
|
201
|
-
|
|
202
|
-
tracker_data.append({
|
|
203
|
-
"color": color,
|
|
204
|
-
"tooltip": f"{current_date.strftime('%Y-%m-%d')}: {activity_count} active users ({level})"
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
current_date += timedelta(days=1)
|
|
208
|
-
|
|
209
|
-
return tracker_data
|
|
210
|
-
|
|
211
|
-
except Exception as e:
|
|
212
|
-
logger.error(f"Error getting activity tracker data: {e}")
|
|
213
|
-
return self._get_empty_tracker_data()
|
|
214
|
-
|
|
215
|
-
def _get_empty_tracker_data(self) -> List[Dict[str, str]]:
|
|
216
|
-
"""Get empty tracker data (365 days of no activity)."""
|
|
217
|
-
tracker_data = []
|
|
218
|
-
for i in range(365):
|
|
219
|
-
tracker_data.append({
|
|
220
|
-
"color": "bg-base-200 dark:bg-base-700",
|
|
221
|
-
"tooltip": f"Day {i + 1}: No data available"
|
|
222
|
-
})
|
|
223
|
-
return tracker_data
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Django commands callbacks.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import logging
|
|
6
|
-
from typing import Any, Dict
|
|
7
|
-
|
|
8
|
-
from .base import get_available_commands, get_commands_by_category
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger(__name__)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class CommandsCallbacks:
|
|
14
|
-
"""Django commands callbacks."""
|
|
15
|
-
|
|
16
|
-
def get_django_commands(self) -> Dict[str, Any]:
|
|
17
|
-
"""Get Django management commands information."""
|
|
18
|
-
try:
|
|
19
|
-
commands = get_available_commands()
|
|
20
|
-
categorized = get_commands_by_category()
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
"commands": commands,
|
|
24
|
-
"categorized": categorized,
|
|
25
|
-
"total_commands": len(commands),
|
|
26
|
-
"categories": list(categorized.keys()),
|
|
27
|
-
"core_commands": len([cmd for cmd in commands if cmd['is_core']]),
|
|
28
|
-
"custom_commands": len([cmd for cmd in commands if cmd['is_custom']]),
|
|
29
|
-
}
|
|
30
|
-
except Exception as e:
|
|
31
|
-
logger.error(f"Error getting Django commands: {e}")
|
|
32
|
-
# Return safe fallback to prevent dashboard from breaking
|
|
33
|
-
return {
|
|
34
|
-
"commands": [],
|
|
35
|
-
"categorized": {},
|
|
36
|
-
"total_commands": 0,
|
|
37
|
-
"categories": [],
|
|
38
|
-
"core_commands": 0,
|
|
39
|
-
"custom_commands": 0,
|
|
40
|
-
}
|
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Main Unfold Dashboard Callbacks
|
|
3
|
-
|
|
4
|
-
Combines all callback modules into a single interface.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import json
|
|
8
|
-
import logging
|
|
9
|
-
from typing import Any, Dict
|
|
10
|
-
|
|
11
|
-
from django.template.loader import render_to_string
|
|
12
|
-
from django.utils import timezone
|
|
13
|
-
|
|
14
|
-
from django_cfg.core.state import get_current_config
|
|
15
|
-
from django_cfg.modules.django_dashboard.debug import save_dashboard_render
|
|
16
|
-
from django_cfg.modules.django_dashboard.sections.commands import CommandsSection
|
|
17
|
-
from django_cfg.modules.django_dashboard.sections.documentation import DocumentationSection
|
|
18
|
-
|
|
19
|
-
# Import new dashboard sections
|
|
20
|
-
from django_cfg.modules.django_dashboard.sections.overview import OverviewSection
|
|
21
|
-
from django_cfg.modules.django_dashboard.sections.stats import StatsSection
|
|
22
|
-
from django_cfg.modules.django_dashboard.sections.system import SystemSection
|
|
23
|
-
from django_cfg.modules.django_dashboard.sections.widgets import WidgetsSection
|
|
24
|
-
|
|
25
|
-
from ...base import BaseCfgModule
|
|
26
|
-
from ..models.dashboard import DashboardData
|
|
27
|
-
from .actions import ActionsCallbacks
|
|
28
|
-
from .base import get_user_admin_urls
|
|
29
|
-
from .charts import ChartsCallbacks
|
|
30
|
-
from .commands import CommandsCallbacks
|
|
31
|
-
from .apizones import OpenAPIClientCallbacks
|
|
32
|
-
from .statistics import StatisticsCallbacks
|
|
33
|
-
from .system import SystemCallbacks
|
|
34
|
-
from .users import UsersCallbacks
|
|
35
|
-
|
|
36
|
-
logger = logging.getLogger(__name__)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class UnfoldCallbacks(
|
|
40
|
-
BaseCfgModule,
|
|
41
|
-
StatisticsCallbacks,
|
|
42
|
-
SystemCallbacks,
|
|
43
|
-
ActionsCallbacks,
|
|
44
|
-
ChartsCallbacks,
|
|
45
|
-
CommandsCallbacks,
|
|
46
|
-
OpenAPIClientCallbacks,
|
|
47
|
-
UsersCallbacks
|
|
48
|
-
):
|
|
49
|
-
"""
|
|
50
|
-
Main Unfold dashboard callbacks with full system monitoring.
|
|
51
|
-
|
|
52
|
-
Combines all callback modules using multiple inheritance for
|
|
53
|
-
clean separation of concerns while maintaining a single interface.
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
def main_dashboard_callback(self, request, context: Dict[str, Any]) -> Dict[str, Any]:
|
|
57
|
-
"""
|
|
58
|
-
Main dashboard callback function with comprehensive system data.
|
|
59
|
-
|
|
60
|
-
Returns all dashboard data as Pydantic models for type safety.
|
|
61
|
-
"""
|
|
62
|
-
try:
|
|
63
|
-
# Get current config for debug and environment settings
|
|
64
|
-
config = get_current_config()
|
|
65
|
-
|
|
66
|
-
# Log debug status
|
|
67
|
-
debug_enabled = config and config.debug
|
|
68
|
-
logger.info(f"[DEBUG MODE] Dashboard rendering with debug={debug_enabled} (config.debug={getattr(config, 'debug', 'N/A')})")
|
|
69
|
-
|
|
70
|
-
# Get dashboard data first
|
|
71
|
-
user_stats = self.get_user_statistics()
|
|
72
|
-
support_stats = self.get_support_statistics()
|
|
73
|
-
system_health = self.get_system_health()
|
|
74
|
-
quick_actions = self.get_quick_actions()
|
|
75
|
-
|
|
76
|
-
# Parse time range from query parameters (default: 7 days)
|
|
77
|
-
try:
|
|
78
|
-
time_range = int(request.GET.get('range', 7))
|
|
79
|
-
# Validate range
|
|
80
|
-
if time_range not in [7, 30, 90]:
|
|
81
|
-
time_range = 7
|
|
82
|
-
except (ValueError, TypeError):
|
|
83
|
-
time_range = 7
|
|
84
|
-
|
|
85
|
-
# Create navigation for time range filter
|
|
86
|
-
navigation = [
|
|
87
|
-
{
|
|
88
|
-
"title": "7 Days",
|
|
89
|
-
"link": "?range=7",
|
|
90
|
-
"active": time_range == 7,
|
|
91
|
-
"icon": "calendar_today"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"title": "30 Days",
|
|
95
|
-
"link": "?range=30",
|
|
96
|
-
"active": time_range == 30,
|
|
97
|
-
"icon": "date_range"
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
"title": "90 Days",
|
|
101
|
-
"link": "?range=90",
|
|
102
|
-
"active": time_range == 90,
|
|
103
|
-
"icon": "event"
|
|
104
|
-
},
|
|
105
|
-
]
|
|
106
|
-
|
|
107
|
-
# Render new dashboard sections
|
|
108
|
-
try:
|
|
109
|
-
# Create overview section and pass quick_actions + time_range + navigation
|
|
110
|
-
overview_sec = OverviewSection(request)
|
|
111
|
-
# Add quick_actions, time_range, and navigation to render context
|
|
112
|
-
overview_section = overview_sec.render(
|
|
113
|
-
quick_actions=[action.model_dump() for action in quick_actions],
|
|
114
|
-
time_range=time_range,
|
|
115
|
-
navigation=navigation
|
|
116
|
-
)
|
|
117
|
-
except Exception as e:
|
|
118
|
-
logger.error(f"Failed to render overview section: {e}", exc_info=True)
|
|
119
|
-
overview_section = None
|
|
120
|
-
|
|
121
|
-
try:
|
|
122
|
-
stats_section = StatsSection(request).render()
|
|
123
|
-
except Exception as e:
|
|
124
|
-
logger.error(f"Failed to render stats section: {e}", exc_info=True)
|
|
125
|
-
stats_section = None
|
|
126
|
-
|
|
127
|
-
try:
|
|
128
|
-
system_section = SystemSection(request).render()
|
|
129
|
-
except Exception as e:
|
|
130
|
-
logger.error(f"Failed to render system section: {e}", exc_info=True)
|
|
131
|
-
system_section = None
|
|
132
|
-
|
|
133
|
-
try:
|
|
134
|
-
# Generate documentation content first
|
|
135
|
-
doc_section = DocumentationSection(request)
|
|
136
|
-
doc_data = doc_section.get_data_old() # Get markdown/HTML content
|
|
137
|
-
documentation_content = doc_data.get('documentation_content') or doc_data.get('readme_content', '')
|
|
138
|
-
documentation_section = doc_section.render()
|
|
139
|
-
except Exception as e:
|
|
140
|
-
logger.error(f"Failed to render documentation section: {e}", exc_info=True)
|
|
141
|
-
documentation_section = None
|
|
142
|
-
documentation_content = None
|
|
143
|
-
|
|
144
|
-
try:
|
|
145
|
-
# Render commands section with documentation content
|
|
146
|
-
commands_section = CommandsSection(request).render(
|
|
147
|
-
documentation_content=documentation_content
|
|
148
|
-
)
|
|
149
|
-
except Exception as e:
|
|
150
|
-
logger.error(f"Failed to render commands section: {e}", exc_info=True)
|
|
151
|
-
commands_section = None
|
|
152
|
-
|
|
153
|
-
# Extract custom widgets from context if provided by project's dashboard_callback
|
|
154
|
-
custom_widgets = context.get('custom_widgets', [])
|
|
155
|
-
custom_metrics = {}
|
|
156
|
-
|
|
157
|
-
# Extract all metric-like variables from context for widget template resolution
|
|
158
|
-
# This allows dashboard_callback to add metrics like: context['total_users'] = 123
|
|
159
|
-
for key, value in context.items():
|
|
160
|
-
if key not in ['request', 'cards', 'system_health', 'quick_actions'] and isinstance(value, (int, float, str)):
|
|
161
|
-
custom_metrics[key] = value
|
|
162
|
-
|
|
163
|
-
try:
|
|
164
|
-
# Render widgets section with custom widgets and metrics from callback
|
|
165
|
-
widgets_section = WidgetsSection(request).render(
|
|
166
|
-
custom_widgets=custom_widgets,
|
|
167
|
-
custom_metrics=custom_metrics
|
|
168
|
-
)
|
|
169
|
-
except Exception as e:
|
|
170
|
-
logger.error(f"Failed to render widgets section: {e}", exc_info=True)
|
|
171
|
-
widgets_section = None
|
|
172
|
-
|
|
173
|
-
# Combine all stat cards (data already loaded above)
|
|
174
|
-
all_stats = user_stats + support_stats
|
|
175
|
-
|
|
176
|
-
dashboard_data = DashboardData(
|
|
177
|
-
stat_cards=all_stats,
|
|
178
|
-
system_health=system_health,
|
|
179
|
-
quick_actions=quick_actions,
|
|
180
|
-
last_updated=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
181
|
-
environment=getattr(config.environment, 'name', 'development') if config and hasattr(config, 'environment') else "development",
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
# Convert to template context (using to_dict for Unfold compatibility)
|
|
185
|
-
cards_data = [card.to_dict() for card in dashboard_data.stat_cards]
|
|
186
|
-
|
|
187
|
-
context.update({
|
|
188
|
-
# New dashboard sections (rendered HTML)
|
|
189
|
-
"overview_section": overview_section,
|
|
190
|
-
"stats_section": stats_section,
|
|
191
|
-
"system_section": system_section,
|
|
192
|
-
"commands_section": commands_section,
|
|
193
|
-
"documentation_section": documentation_section,
|
|
194
|
-
"widgets_section": widgets_section,
|
|
195
|
-
|
|
196
|
-
# Documentation content for commands tab
|
|
197
|
-
"documentation_content": documentation_content,
|
|
198
|
-
|
|
199
|
-
# Statistics cards
|
|
200
|
-
"cards": cards_data,
|
|
201
|
-
"user_stats": [card.to_dict() for card in user_stats],
|
|
202
|
-
"support_stats": [card.to_dict() for card in support_stats],
|
|
203
|
-
|
|
204
|
-
# System health (convert to dict for template)
|
|
205
|
-
"system_health": {
|
|
206
|
-
item.component + "_status": item.status
|
|
207
|
-
for item in dashboard_data.system_health
|
|
208
|
-
},
|
|
209
|
-
|
|
210
|
-
# Quick actions
|
|
211
|
-
"quick_actions": [
|
|
212
|
-
action.model_dump() for action in dashboard_data.quick_actions
|
|
213
|
-
],
|
|
214
|
-
|
|
215
|
-
# Additional categorized actions
|
|
216
|
-
"admin_actions": [
|
|
217
|
-
action.model_dump()
|
|
218
|
-
for action in dashboard_data.quick_actions
|
|
219
|
-
if action.category == "admin"
|
|
220
|
-
],
|
|
221
|
-
"support_actions": [
|
|
222
|
-
action.model_dump()
|
|
223
|
-
for action in dashboard_data.quick_actions
|
|
224
|
-
if action.category == "support"
|
|
225
|
-
],
|
|
226
|
-
"system_actions": [
|
|
227
|
-
action.model_dump()
|
|
228
|
-
for action in dashboard_data.quick_actions
|
|
229
|
-
if action.category == "system"
|
|
230
|
-
],
|
|
231
|
-
|
|
232
|
-
# OpenAPI Client groups
|
|
233
|
-
"zones_table": {
|
|
234
|
-
"headers": [
|
|
235
|
-
{"label": "Zone"},
|
|
236
|
-
{"label": "Title"},
|
|
237
|
-
{"label": "Apps"},
|
|
238
|
-
{"label": "Endpoints"},
|
|
239
|
-
{"label": "Status"},
|
|
240
|
-
{"label": "Actions"},
|
|
241
|
-
],
|
|
242
|
-
"rows": OpenAPIClientCallbacks().get_openapi_groups_data()[0],
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
# Recent users
|
|
246
|
-
"recent_users": self.get_recent_users(),
|
|
247
|
-
"user_admin_urls": get_user_admin_urls(),
|
|
248
|
-
|
|
249
|
-
# App statistics
|
|
250
|
-
"app_statistics": self.get_app_statistics(),
|
|
251
|
-
|
|
252
|
-
# Django commands
|
|
253
|
-
"django_commands": self.get_django_commands(),
|
|
254
|
-
|
|
255
|
-
# Charts data - serialize to JSON for JavaScript
|
|
256
|
-
"charts": {
|
|
257
|
-
"user_registrations_json": json.dumps(self.get_user_registration_chart_data()),
|
|
258
|
-
"user_activity_json": json.dumps(self.get_user_activity_chart_data()),
|
|
259
|
-
"user_registrations": self.get_user_registration_chart_data(),
|
|
260
|
-
"user_activity": self.get_user_activity_chart_data(),
|
|
261
|
-
},
|
|
262
|
-
|
|
263
|
-
# Activity tracker data
|
|
264
|
-
"activity_tracker": self.get_activity_tracker_data(),
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
# Meta information
|
|
268
|
-
"last_updated": dashboard_data.last_updated,
|
|
269
|
-
"environment": dashboard_data.environment,
|
|
270
|
-
"dashboard_title": "Django CFG Dashboard",
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
# Log charts data for debugging
|
|
274
|
-
# charts_data = context.get('charts', {})
|
|
275
|
-
# # logger.info(f"Charts data added to context: {list(charts_data.keys())}")
|
|
276
|
-
# if 'user_registrations' in charts_data:
|
|
277
|
-
# reg_data = charts_data['user_registrations']
|
|
278
|
-
# logger.info(f"Registration chart labels: {reg_data.get('labels', [])}")
|
|
279
|
-
# if 'user_activity' in charts_data:
|
|
280
|
-
# act_data = charts_data['user_activity']
|
|
281
|
-
# logger.info(f"Activity chart labels: {act_data.get('labels', [])}")
|
|
282
|
-
|
|
283
|
-
# # Log recent users data for debugging
|
|
284
|
-
# recent_users_data = context.get('recent_users', [])
|
|
285
|
-
# logger.info(f"Recent users data count: {len(recent_users_data)}")
|
|
286
|
-
# if recent_users_data:
|
|
287
|
-
# logger.info(f"First user: {recent_users_data[0].get('username', 'N/A')}")
|
|
288
|
-
|
|
289
|
-
# # Log activity tracker data for debugging
|
|
290
|
-
# activity_tracker_data = context.get('activity_tracker', [])
|
|
291
|
-
# logger.info(f"Activity tracker data count: {len(activity_tracker_data)}")
|
|
292
|
-
|
|
293
|
-
# Debug: save full rendered page (only in debug mode)
|
|
294
|
-
# DISABLED: Commenting out dashboard render saving to disk
|
|
295
|
-
# if config and config.debug:
|
|
296
|
-
# try:
|
|
297
|
-
# full_html = render_to_string('admin/index.html', context, request)
|
|
298
|
-
# save_dashboard_render(full_html, name='dashboard_full_page', context=context)
|
|
299
|
-
# except Exception as e:
|
|
300
|
-
# logger.error(f"Failed to save full dashboard render: {e}", exc_info=True)
|
|
301
|
-
|
|
302
|
-
return context
|
|
303
|
-
|
|
304
|
-
except Exception as e:
|
|
305
|
-
logger.error(f"Dashboard callback error: {e}")
|
|
306
|
-
# Return minimal safe defaults
|
|
307
|
-
context.update({
|
|
308
|
-
"cards": [
|
|
309
|
-
{
|
|
310
|
-
"title": "System Error",
|
|
311
|
-
"value": "N/A",
|
|
312
|
-
"icon": "error",
|
|
313
|
-
"color": "danger",
|
|
314
|
-
"description": "Dashboard data unavailable"
|
|
315
|
-
}
|
|
316
|
-
],
|
|
317
|
-
"system_health": {},
|
|
318
|
-
"quick_actions": [],
|
|
319
|
-
"last_updated": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
320
|
-
"error": f"Dashboard error: {str(e)}",
|
|
321
|
-
})
|
|
322
|
-
return context
|