django-cfg 1.2.7__py3-none-any.whl → 1.2.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/urls.py +2 -2
  3. django_cfg/modules/django_unfold/callbacks/__init__.py +9 -0
  4. django_cfg/modules/django_unfold/callbacks/actions.py +50 -0
  5. django_cfg/modules/django_unfold/callbacks/base.py +98 -0
  6. django_cfg/modules/django_unfold/callbacks/charts.py +224 -0
  7. django_cfg/modules/django_unfold/callbacks/commands.py +40 -0
  8. django_cfg/modules/django_unfold/callbacks/main.py +191 -0
  9. django_cfg/modules/django_unfold/callbacks/revolution.py +76 -0
  10. django_cfg/modules/django_unfold/callbacks/statistics.py +240 -0
  11. django_cfg/modules/django_unfold/callbacks/system.py +180 -0
  12. django_cfg/modules/django_unfold/callbacks/users.py +65 -0
  13. django_cfg/modules/django_unfold/models/config.py +10 -3
  14. django_cfg/modules/django_unfold/tailwind.py +68 -0
  15. django_cfg/templates/admin/components/action_grid.html +49 -0
  16. django_cfg/templates/admin/components/card.html +50 -0
  17. django_cfg/templates/admin/components/data_table.html +67 -0
  18. django_cfg/templates/admin/components/metric_card.html +39 -0
  19. django_cfg/templates/admin/components/modal.html +58 -0
  20. django_cfg/templates/admin/components/progress_bar.html +25 -0
  21. django_cfg/templates/admin/components/section_header.html +26 -0
  22. django_cfg/templates/admin/components/stat_item.html +32 -0
  23. django_cfg/templates/admin/components/stats_grid.html +72 -0
  24. django_cfg/templates/admin/components/status_badge.html +28 -0
  25. django_cfg/templates/admin/components/user_avatar.html +27 -0
  26. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +7 -7
  27. django_cfg/templates/admin/snippets/components/activity_tracker.html +48 -11
  28. django_cfg/templates/admin/snippets/components/charts_section.html +63 -13
  29. django_cfg/templates/admin/snippets/components/django_commands.html +18 -18
  30. django_cfg/templates/admin/snippets/components/quick_actions.html +3 -47
  31. django_cfg/templates/admin/snippets/components/recent_activity.html +28 -38
  32. django_cfg/templates/admin/snippets/components/recent_users_table.html +22 -53
  33. django_cfg/templates/admin/snippets/components/stats_cards.html +2 -66
  34. django_cfg/templates/admin/snippets/components/system_health.html +13 -63
  35. django_cfg/templates/admin/snippets/components/system_metrics.html +8 -25
  36. django_cfg/templates/admin/snippets/tabs/commands_tab.html +1 -1
  37. django_cfg/templates/admin/snippets/tabs/overview_tab.html +4 -4
  38. django_cfg/templates/admin/snippets/zones/zones_table.html +12 -33
  39. django_cfg/templatetags/django_cfg.py +2 -1
  40. {django_cfg-1.2.7.dist-info → django_cfg-1.2.8.dist-info}/METADATA +2 -1
  41. {django_cfg-1.2.7.dist-info → django_cfg-1.2.8.dist-info}/RECORD +44 -24
  42. django_cfg/modules/django_unfold/callbacks.py +0 -795
  43. {django_cfg-1.2.7.dist-info → django_cfg-1.2.8.dist-info}/WHEEL +0 -0
  44. {django_cfg-1.2.7.dist-info → django_cfg-1.2.8.dist-info}/entry_points.txt +0 -0
  45. {django_cfg-1.2.7.dist-info → django_cfg-1.2.8.dist-info}/licenses/LICENSE +0 -0
@@ -1,16 +1,11 @@
1
1
  {% load unfold %}
2
2
 
3
- <!-- Charts Section -->
3
+ <!-- Charts Section using reusable components -->
4
4
  <div class="mb-8 w-full">
5
- <div class="flex items-center mb-6">
6
- <div class="flex items-center justify-center w-8 h-8 bg-blue-100 dark:bg-blue-900/20 rounded-lg mr-3">
7
- <span class="material-icons text-blue-600 dark:text-blue-400 text-lg">analytics</span>
8
- </div>
9
- <h2 class="text-xl font-semibold text-font-important-light dark:text-font-important-dark">
10
- Analytics Overview
11
- </h2>
12
- </div>
5
+ {% include 'admin/components/section_header.html' with title='Analytics Overview' icon='analytics' icon_color='blue' %}
13
6
 
7
+
8
+ {% if charts %}
14
9
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
15
10
  <!-- User Registration Chart -->
16
11
  <div class="group">
@@ -19,8 +14,32 @@
19
14
  <span class="material-icons text-primary-600 dark:text-primary-500 mr-2">trending_up</span>
20
15
  <span class="text-sm text-font-subtle-light dark:text-font-subtle-dark">Growth Trends</span>
21
16
  </div>
22
- {% component "unfold/components/chart/line.html" with data=charts.user_registrations height=300 %}
23
- {% endcomponent %}
17
+ {% if charts.user_registrations %}
18
+ {% component "unfold/components/chart/line.html" with data=charts.user_registrations_json height=300 %}
19
+ {% endcomponent %}
20
+
21
+ <!-- Fallback data table if chart doesn't render -->
22
+ <div class="mt-4 text-xs text-font-subtle-light dark:text-font-subtle-dark">
23
+ <div class="flex justify-between items-center mb-2">
24
+ <span class="font-medium">Data Preview:</span>
25
+ <span>{{ charts.user_registrations.datasets.0.label }}</span>
26
+ </div>
27
+ <div class="grid grid-cols-7 gap-1 text-center">
28
+ {% for label in charts.user_registrations.labels %}
29
+ <div class="bg-base-100 dark:bg-base-700 p-1 rounded text-xs">{{ label }}</div>
30
+ {% endfor %}
31
+ </div>
32
+ <div class="grid grid-cols-7 gap-1 text-center mt-1">
33
+ {% for value in charts.user_registrations.datasets.0.data %}
34
+ <div class="bg-primary-50 dark:bg-primary-900/20 p-1 rounded text-xs font-medium">{{ value }}</div>
35
+ {% endfor %}
36
+ </div>
37
+ </div>
38
+ {% else %}
39
+ <div class="h-[300px] flex items-center justify-center bg-base-50 dark:bg-base-800 rounded-lg border border-base-200 dark:border-base-700">
40
+ <p class="text-font-subtle-light dark:text-font-subtle-dark">No registration data available</p>
41
+ </div>
42
+ {% endif %}
24
43
  {% endcomponent %}
25
44
  </div>
26
45
 
@@ -31,9 +50,40 @@
31
50
  <span class="material-icons text-green-600 dark:text-green-400 mr-2">bar_chart</span>
32
51
  <span class="text-sm text-font-subtle-light dark:text-font-subtle-dark">Activity Levels</span>
33
52
  </div>
34
- {% component "unfold/components/chart/bar.html" with data=charts.user_activity height=300 %}
35
- {% endcomponent %}
53
+ {% if charts.user_activity %}
54
+ {% component "unfold/components/chart/bar.html" with data=charts.user_activity_json height=300 %}
55
+ {% endcomponent %}
56
+
57
+ <!-- Fallback data table if chart doesn't render -->
58
+ <div class="mt-4 text-xs text-font-subtle-light dark:text-font-subtle-dark">
59
+ <div class="flex justify-between items-center mb-2">
60
+ <span class="font-medium">Data Preview:</span>
61
+ <span>{{ charts.user_activity.datasets.0.label }}</span>
62
+ </div>
63
+ <div class="grid grid-cols-7 gap-1 text-center">
64
+ {% for label in charts.user_activity.labels %}
65
+ <div class="bg-base-100 dark:bg-base-700 p-1 rounded text-xs">{{ label }}</div>
66
+ {% endfor %}
67
+ </div>
68
+ <div class="grid grid-cols-7 gap-1 text-center mt-1">
69
+ {% for value in charts.user_activity.datasets.0.data %}
70
+ <div class="bg-green-50 dark:bg-green-900/20 p-1 rounded text-xs font-medium">{{ value }}</div>
71
+ {% endfor %}
72
+ </div>
73
+ </div>
74
+ {% else %}
75
+ <div class="h-[300px] flex items-center justify-center bg-base-50 dark:bg-base-800 rounded-lg border border-base-200 dark:border-base-700">
76
+ <p class="text-font-subtle-light dark:text-font-subtle-dark">No activity data available</p>
77
+ </div>
78
+ {% endif %}
36
79
  {% endcomponent %}
37
80
  </div>
38
81
  </div>
82
+ {% else %}
83
+ <div class="bg-base-50 dark:bg-base-800 rounded-lg border border-base-200 dark:border-base-700 p-8 text-center">
84
+ <span class="material-icons text-4xl text-base-400 dark:text-base-500 mb-4">analytics</span>
85
+ <h3 class="text-lg font-medium text-font-default-light dark:text-font-default-dark mb-2">No Chart Data</h3>
86
+ <p class="text-font-subtle-light dark:text-font-subtle-dark">Charts data is not available in the context</p>
87
+ </div>
88
+ {% endif %}
39
89
  </div>
@@ -19,7 +19,7 @@
19
19
  <!-- Commands by Category -->
20
20
  <div class="space-y-4">
21
21
  {% for category, commands in django_commands.categorized.items %}
22
- <div class="bg-white dark:bg-base-900 rounded-default border border-base-200 dark:border-base-700 overflow-hidden shadow-sm mb-4">
22
+ <div class="bg-white dark:bg-base-900 rounded-lg border border-base-200 dark:border-base-700 overflow-hidden shadow-sm mb-4">
23
23
  <!-- Category Header -->
24
24
  <button
25
25
  onclick="toggleCategory('{{ category }}')"
@@ -30,7 +30,7 @@
30
30
  <h3 class="text-lg font-semibold text-font-important-light dark:text-font-important-dark capitalize">
31
31
  {{ category|title }}
32
32
  </h3>
33
- <span class="ml-3 text-sm text-font-subtle-light dark:text-font-subtle-dark bg-base-100 dark:bg-base-700 px-2 py-1 rounded-default">
33
+ <span class="ml-3 text-sm text-font-subtle-light dark:text-font-subtle-dark bg-base-100 dark:bg-base-700 px-2 py-1 rounded-lg">
34
34
  {{ commands|length }} commands
35
35
  </span>
36
36
  </div>
@@ -44,21 +44,21 @@
44
44
  <div class="p-4">
45
45
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
46
46
  {% for command in commands %}
47
- <div class="bg-white dark:bg-base-900 rounded-default border border-base-200 dark:border-base-700 hover:shadow-lg dark:hover:shadow-base-900/50 transition-all duration-200 overflow-hidden">
47
+ <div class="bg-white dark:bg-base-900 rounded-lg border border-base-200 dark:border-base-700 hover:shadow-lg dark:hover:shadow-base-900/50 transition-all duration-200 overflow-hidden">
48
48
  <!-- Card Header -->
49
49
  <div class="p-4 border-b border-base-100 dark:border-base-700">
50
50
  <div class="flex items-center justify-between mb-2">
51
- <code class="text-sm font-mono bg-base-100 dark:bg-base-700 px-2 py-1 rounded-default text-font-default-light dark:text-font-default-dark">
51
+ <code class="text-sm font-mono bg-base-100 dark:bg-base-700 px-2 py-1 rounded-lg text-font-default-light dark:text-font-default-dark">
52
52
  {{ command.name }}
53
53
  </code>
54
54
  <div class="flex items-center space-x-1">
55
55
  {% if command.is_core %}
56
- <span class="text-xs bg-primary-100 dark:bg-primary-900/20 text-primary-600 dark:text-primary-400 px-2 py-1 rounded-default">
56
+ <span class="text-xs bg-primary-100 dark:bg-primary-900/20 text-primary-600 dark:text-primary-400 px-2 py-1 rounded-lg">
57
57
  Core
58
58
  </span>
59
59
  {% endif %}
60
60
  {% if command.is_custom %}
61
- <span class="text-xs bg-indigo-100 dark:bg-indigo-900/20 text-indigo-600 dark:text-indigo-400 px-2 py-1 rounded-default">
61
+ <span class="text-xs bg-indigo-100 dark:bg-indigo-900/20 text-indigo-600 dark:text-indigo-400 px-2 py-1 rounded-lg">
62
62
  Custom
63
63
  </span>
64
64
  {% endif %}
@@ -83,7 +83,7 @@
83
83
  {% if command.usage %}
84
84
  <div class="mb-3">
85
85
  <span class="text-xs text-font-subtle-light dark:text-font-subtle-dark font-medium">Usage:</span>
86
- <code class="block text-xs font-mono bg-base-50 dark:bg-base-700 px-2 py-1 rounded-default mt-1 text-font-default-light dark:text-font-default-dark">
86
+ <code class="block text-xs font-mono bg-base-50 dark:bg-base-700 px-2 py-1 rounded-lg mt-1 text-font-default-light dark:text-font-default-dark">
87
87
  {{ command.usage }}
88
88
  </code>
89
89
  </div>
@@ -103,14 +103,14 @@
103
103
  <div class="flex gap-2">
104
104
  <button
105
105
  onclick="copyToClipboard('python manage.py {{ command.name }}')"
106
- class="flex-1 inline-flex items-center justify-center px-3 py-2 bg-base-100 dark:bg-base-700 hover:bg-base-200 dark:hover:bg-base-600 text-font-default-light dark:text-font-default-dark rounded-default text-xs font-medium transition-colors"
106
+ class="flex-1 inline-flex items-center justify-center px-3 py-2 bg-base-100 dark:bg-base-700 hover:bg-base-200 dark:hover:bg-base-600 text-font-default-light dark:text-font-default-dark rounded-lg text-xs font-medium transition-colors"
107
107
  title="Copy command to clipboard">
108
108
  <span class="material-icons text-xs mr-1">content_copy</span>
109
109
  Copy
110
110
  </button>
111
111
  <button
112
112
  onclick="executeCommand('{{ command.name }}')"
113
- class="flex-1 inline-flex items-center justify-center px-3 py-2 bg-green-600 hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600 text-white rounded-default text-xs font-medium transition-colors"
113
+ class="flex-1 inline-flex items-center justify-center px-3 py-2 bg-green-600 hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600 text-white rounded-lg text-xs font-medium transition-colors"
114
114
  title="Execute command">
115
115
  <span class="material-icons text-xs mr-1">play_arrow</span>
116
116
  Run
@@ -186,13 +186,13 @@
186
186
  </div>
187
187
 
188
188
  <!-- Command Execution Modal -->
189
- <div id="commandModal" class="fixed inset-0 bg-base-900/80 backdrop-blur-sm hidden z-50">
189
+ <div id="commandModal" class="fixed inset-0 bg-black/80 backdrop-blur-sm hidden z-50">
190
190
  <div class="flex items-center justify-center min-h-screen p-4">
191
- <div class="bg-white dark:bg-base-900 rounded-default shadow-2xl max-w-4xl w-full h-[80vh] flex flex-col border border-base-200 dark:border-base-700">
191
+ <div class="bg-white dark:bg-base-900 rounded-lg shadow-2xl max-w-4xl w-full max-h-[80vh] flex flex-col border border-base-200 dark:border-base-700">
192
192
  <!-- Modal Header -->
193
- <div class="flex items-center justify-between p-4 border-b border-base-200 dark:border-base-700 bg-base-50 dark:bg-base-800 flex-shrink-0">
193
+ <div class="flex items-center justify-between p-4 border-b border-base-200 dark:border-base-700 bg-base-50 dark:bg-base-800">
194
194
  <div class="flex items-center space-x-3">
195
- <div class="flex items-center justify-center w-10 h-10 bg-primary-100 dark:bg-primary-900/20 rounded-default">
195
+ <div class="flex items-center justify-center w-10 h-10 bg-primary-100 dark:bg-primary-900/20 rounded-lg">
196
196
  <span class="material-icons text-primary-600 dark:text-primary-400">terminal</span>
197
197
  </div>
198
198
  <div>
@@ -204,25 +204,25 @@
204
204
  </p>
205
205
  </div>
206
206
  </div>
207
- <button onclick="closeCommandModal()" class="p-2 text-font-subtle-light dark:text-font-subtle-dark hover:text-font-default-light dark:hover:text-font-default-dark hover:bg-base-100 dark:hover:bg-base-700 rounded-default transition-colors">
207
+ <button onclick="closeCommandModal()" class="p-2 text-font-subtle-light dark:text-font-subtle-dark hover:text-font-default-light dark:hover:text-font-default-dark hover:bg-base-100 dark:hover:bg-base-700 rounded-lg transition-colors">
208
208
  <span class="material-icons">close</span>
209
209
  </button>
210
210
  </div>
211
211
 
212
212
  <!-- Modal Body -->
213
- <div class="flex-1 min-h-0 p-4">
214
- <div id="commandOutput" class="bg-base-100 dark:bg-base-800 rounded-default border border-base-200 dark:border-base-700 min-h-[200px] max-h-[60vh] overflow-y-auto p-4 text-sm font-mono text-font-default-light dark:text-font-default-dark whitespace-pre-wrap leading-relaxed break-words overflow-wrap-anywhere" style="max-height: 60vh;"></div>
213
+ <div class="flex-1 p-4" style="min-height: 0;">
214
+ <div id="commandOutput" class="bg-base-100 dark:bg-base-800 rounded-lg border border-base-200 dark:border-base-700 overflow-y-auto p-4 text-sm font-mono text-font-default-light dark:text-font-default-dark whitespace-pre-wrap leading-relaxed break-words" style="height: calc(80vh - 200px); max-height: 60vh;"></div>
215
215
  </div>
216
216
 
217
217
  <!-- Modal Footer -->
218
- <div class="flex items-center justify-between p-4 border-t border-base-200 dark:border-base-700 bg-base-50 dark:bg-base-800 flex-shrink-0">
218
+ <div class="flex items-center justify-between p-4 border-t border-base-200 dark:border-base-700 bg-base-50 dark:bg-base-800">
219
219
  <div class="flex items-center space-x-3">
220
220
  <div id="commandStatus" class="flex items-center">
221
221
  <div class="w-3 h-3 bg-yellow-500 rounded-full mr-2 animate-pulse"></div>
222
222
  <span class="text-sm font-medium text-font-default-light dark:text-font-default-dark">Executing...</span>
223
223
  </div>
224
224
  </div>
225
- <button onclick="closeCommandModal()" class="px-4 py-2 bg-base-100 dark:bg-base-700 hover:bg-base-200 dark:hover:bg-base-600 text-font-default-light dark:text-font-default-dark rounded-default transition-colors font-medium">
225
+ <button onclick="closeCommandModal()" class="px-4 py-2 bg-base-100 dark:bg-base-700 hover:bg-base-200 dark:hover:bg-base-600 text-font-default-light dark:text-font-default-dark rounded-lg transition-colors font-medium">
226
226
  Close
227
227
  </button>
228
228
  </div>
@@ -1,55 +1,11 @@
1
1
  {% load unfold %}
2
2
 
3
- <!-- Quick Actions Section with semantic colors -->
3
+ <!-- Quick Actions Section using reusable components -->
4
4
  {% if quick_actions %}
5
5
  <div class="mt-8 w-full">
6
- <div class="flex items-center mb-6">
7
- <div class="flex items-center justify-center w-8 h-8 bg-amber-100 dark:bg-amber-900/20 rounded-lg mr-3">
8
- <span class="material-icons text-amber-600 dark:text-amber-400 text-lg">flash_on</span>
9
- </div>
10
- <h2 class="text-xl font-semibold text-font-important-light dark:text-font-important-dark">
11
- Quick Actions
12
- </h2>
13
- </div>
6
+ {% include 'admin/components/section_header.html' with title='Quick Actions' icon='flash_on' icon_color='amber' %}
14
7
 
15
- <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
16
- {% for action in quick_actions %}
17
- <a href="{{ action.link }}"
18
- class="group flex items-center p-4 bg-white dark:bg-base-900 rounded-lg border border-base-200 dark:border-base-700 hover:border-primary-600 dark:hover:border-primary-500 hover:shadow-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2">
19
- <div class="flex-shrink-0 mr-4">
20
- <div class="p-2 rounded-lg " {% if action.color == 'primary' %}bg-primary-100 dark:bg-primary-900/20 group-hover:bg-primary-200 dark:group-hover:bg-primary-800/30
21
- {% elif action.color == 'success' %}bg-green-100 dark:bg-green-900/20 group-hover:bg-green-200 dark:group-hover:bg-green-800/30
22
- {% elif action.color == 'warning' %}bg-amber-100 dark:bg-amber-900/20 group-hover:bg-amber-200 dark:group-hover:bg-amber-800/30
23
- {% elif action.color == 'danger' %}bg-red-100 dark:bg-red-900/20 group-hover:bg-red-200 dark:group-hover:bg-red-800/30
24
- {% else %}bg-base-100 dark:bg-base-800 group-hover:bg-base-200 dark:group-hover:bg-base-700{% endif %}
25
- transition-colors duration-200">
26
- <span class="material-icons text-lg " {% if action.color == 'primary' %}text-primary-600 dark:text-primary-400
27
- {% elif action.color == 'success' %}text-green-600 dark:text-green-400
28
- {% elif action.color == 'warning' %}text-amber-600 dark:text-amber-400
29
- {% elif action.color == 'danger' %}text-red-600 dark:text-red-400
30
- {% else %}text-font-subtle-light dark:text-font-subtle-dark{% endif %}">
31
- {{ action.icon }}
32
- </span>
33
- </div>
34
- </div>
35
- <div class="flex-1 min-w-0">
36
- <h3 class="text-sm font-medium text-font-default-light dark:text-font-default-dark group-hover:text-primary-600 dark:group-hover:text-primary-500 transition-colors duration-200">
37
- {{ action.title }}
38
- </h3>
39
- {% if action.description %}
40
- <p class="text-xs text-font-subtle-light dark:text-font-subtle-dark mt-1 line-clamp-2">
41
- {{ action.description }}
42
- </p>
43
- {% endif %}
44
- </div>
45
- <div class="flex-shrink-0 ml-2">
46
- <span class="material-icons text-base-400 dark:text-base-500 group-hover:text-primary-600 dark:group-hover:text-primary-500 transition-colors duration-200">
47
- arrow_forward
48
- </span>
49
- </div>
50
- </a>
51
- {% endfor %}
52
- </div>
8
+ {% include 'admin/components/action_grid.html' with actions=quick_actions cols=3 xl_cols=4 %}
53
9
 
54
10
  <!-- Additional Action Categories -->
55
11
  {% if admin_actions or user_actions or system_actions %}
@@ -1,45 +1,35 @@
1
1
  {% load unfold %}
2
2
 
3
- <!-- Recent Activity Section -->
4
- {% if recent_activity.recent_users %}
5
- <div class="mt-8 w-full">
6
- <h2 class="text-xl font-semibold text-font-important-light dark:text-font-important-dark mb-4">
7
- Recent Activity
8
- </h2>
9
- <div class="bg-white dark:bg-base-900 rounded-lg border border-base-200 dark:border-base-700 w-full shadow-xs">
10
- <div class="p-4">
11
- <h3 class="text-lg font-medium text-font-default-light dark:text-font-default-dark mb-3">
12
- Recent User Registrations
13
- </h3>
14
- <div class="space-y-3">
15
- {% for user in recent_activity.recent_users %}
16
- <div class="flex items-center justify-between p-3 bg-base-50 dark:bg-base-800 rounded-lg">
17
- <div class="flex items-center space-x-3">
18
- <div class="w-8 h-8 bg-blue-100 dark:bg-blue-900/20 rounded-full flex items-center justify-center">
19
- <span class="text-sm font-medium text-blue-600 dark:text-blue-400"> {{ user.username|first|upper }}
20
- </span>
21
- </div>
22
- <div>
23
- <p class="text-sm font-medium text-font-default-light dark:text-font-default-dark">
24
- {{ user.username }}
25
- </p>
26
- <p class="text-xs text-font-subtle-light dark:text-font-subtle-dark">
27
- {{ user.email }}
28
- </p>
29
- </div>
30
- </div>
31
- <div class="flex items-center space-x-2">
32
- <span class="px-2 py-1 text-xs font-medium rounded-full " {% if user.is_active %}bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400{% else %}bg-red-100 dark:bg-red-900/20 text-red-600 dark:text-red-400{% endif %}">
33
- {% if user.is_active %}Active{% else %}Inactive{% endif %}
34
- </span>
35
- <span class="text-xs text-font-subtle-light dark:text-font-subtle-dark">
36
- {{ user.date_joined|date:"M d, Y" }}
37
- </span>
38
- </div>
39
- </div>
40
- {% endfor %}
3
+ <!-- Recent Activity Content -->
4
+ {% if recent_users %}
5
+ <div class="space-y-3">
6
+ {% for user in recent_users %}
7
+ <div class="flex items-center justify-between p-3 bg-base-50 dark:bg-base-800 rounded-lg">
8
+ <div class="flex items-center space-x-3">
9
+ {% include 'admin/components/user_avatar.html' with name=user.username color='blue' size='8' %}
10
+ <div>
11
+ <p class="text-sm font-medium text-font-default-light dark:text-font-default-dark">
12
+ {{ user.username }}
13
+ </p>
14
+ <p class="text-xs text-font-subtle-light dark:text-font-subtle-dark">
15
+ {{ user.email }}
16
+ </p>
17
+ </div>
18
+ </div>
19
+ <div class="flex items-center space-x-2">
20
+ {% include 'admin/components/status_badge.html' with status=user.is_active|yesno:'active,inactive' %}
21
+ <span class="text-xs text-font-subtle-light dark:text-font-subtle-dark">
22
+ {{ user.date_joined|date:"M d, Y" }}
23
+ </span>
41
24
  </div>
42
25
  </div>
26
+ {% endfor %}
27
+ </div>
28
+ {% else %}
29
+ <div class="flex items-center justify-center p-8 bg-base-50 dark:bg-base-800 rounded-lg border border-base-200 dark:border-base-700">
30
+ <div class="text-center">
31
+ <span class="material-icons text-4xl text-base-400 dark:text-base-500 mb-2">history</span>
32
+ <p class="text-font-subtle-light dark:text-font-subtle-dark">No recent activity available</p>
43
33
  </div>
44
34
  </div>
45
35
  {% endif %}
@@ -1,6 +1,21 @@
1
1
  {% load unfold %}
2
2
 
3
- <!-- Recent Users Table with semantic colors -->
3
+ <!-- Recent Users Table using reusable components -->
4
+ {% capture as table_actions silent %}
5
+ <span class="text-xs text-font-subtle-light dark:text-font-subtle-dark">Last 24 hours</span>
6
+ {% if user_admin_urls %}
7
+ <a href="{{ user_admin_urls.list }}" class="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-500 dark:hover:text-primary-400 flex items-center">
8
+ View all
9
+ <span class="material-icons text-xs ml-1">arrow_forward</span>
10
+ </a>
11
+ {% else %}
12
+ <a href="/admin/accounts/customuser/" class="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-500 dark:hover:text-primary-400 flex items-center">
13
+ View all
14
+ <span class="material-icons text-xs ml-1">arrow_forward</span>
15
+ </a>
16
+ {% endif %}
17
+ {% endcapture %}
18
+
4
19
  <div class="bg-white dark:bg-base-900 rounded-lg border border-base-200 dark:border-base-700 overflow-hidden shadow-xs">
5
20
  <!-- Card Header -->
6
21
  <div class="px-6 py-4 border-b border-base-200 dark:border-base-700 bg-base-50 dark:bg-base-800">
@@ -10,18 +25,7 @@
10
25
  <h3 class="text-lg font-semibold text-font-important-light dark:text-font-important-dark">Recent Users</h3>
11
26
  </div>
12
27
  <div class="flex items-center space-x-2">
13
- <span class="text-xs text-font-subtle-light dark:text-font-subtle-dark">Last 24 hours</span>
14
- {% if user_admin_urls %}
15
- <a href="{{ user_admin_urls.list }}" class="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-500 dark:hover:text-primary-400 flex items-center">
16
- View all
17
- <span class="material-icons text-xs ml-1">arrow_forward</span>
18
- </a>
19
- {% else %}
20
- <a href="/admin/accounts/customuser/" class="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-500 dark:hover:text-primary-400 flex items-center">
21
- View all
22
- <span class="material-icons text-xs ml-1">arrow_forward</span>
23
- </a>
24
- {% endif %}
28
+ {{ table_actions }}
25
29
  </div>
26
30
  </div>
27
31
  </div>
@@ -47,53 +51,18 @@
47
51
  {% for user in recent_users %}
48
52
  <tr class="hover:bg-base-100 dark:hover:bg-base-800 transition-colors duration-150">
49
53
  <td class="px-6 py-4 whitespace-nowrap">
50
- <div class="flex items-center">
51
- <div class="h-8 w-8 bg-primary-100 dark:bg-primary-900/20 rounded-full flex items-center justify-center mr-3">
52
- <span class="text-sm font-medium text-primary-600 dark:text-primary-400">
53
- {{ user.username|default:user.email|slice:":1"|upper }}
54
- </span>
55
- </div>
56
- <div>
57
- <div class="text-sm font-medium text-font-default-light dark:text-font-default-dark">
58
- {{ user.username|default:user.email|truncatechars:20 }}
59
- </div>
60
- {% if user.email and user.username %}
61
- <div class="text-xs text-font-subtle-light dark:text-font-subtle-dark">
62
- {{ user.email|truncatechars:30 }}
63
- </div>
64
- {% endif %}
65
- </div>
66
- </div>
54
+ {% include 'admin/components/user_avatar.html' with name=user.username email=user.email show_details=True %}
67
55
  </td>
68
56
  <td class="px-6 py-4 whitespace-nowrap">
69
- {% if user.is_active %}
70
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400">
71
- <span class="material-icons text-xs mr-1">check_circle</span>
72
- Active
73
- </span>
74
- {% else %}
75
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-base-100 dark:bg-base-800 text-font-subtle-light dark:text-font-subtle-dark">
76
- <span class="material-icons text-xs mr-1">cancel</span>
77
- Inactive
78
- </span>
79
- {% endif %}
57
+ {% include 'admin/components/status_badge.html' with status=user.is_active|yesno:'active,inactive' %}
80
58
  </td>
81
59
  <td class="px-6 py-4 whitespace-nowrap">
82
60
  {% if user.is_superuser %}
83
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 dark:bg-red-900/20 text-red-600 dark:text-red-400">
84
- <span class="material-icons text-xs mr-1">admin_panel_settings</span>
85
- Admin
86
- </span>
61
+ {% include 'admin/components/status_badge.html' with status='error' text='Admin' icon='admin_panel_settings' %}
87
62
  {% elif user.is_staff %}
88
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400">
89
- <span class="material-icons text-xs mr-1">manage_accounts</span>
90
- Staff
91
- </span>
63
+ {% include 'admin/components/status_badge.html' with status='info' text='Staff' icon='manage_accounts' %}
92
64
  {% else %}
93
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-base-100 dark:bg-base-800 text-font-subtle-light dark:text-font-subtle-dark">
94
- <span class="material-icons text-xs mr-1">person</span>
95
- User
96
- </span>
65
+ {% include 'admin/components/status_badge.html' with status='' text='User' icon='person' %}
97
66
  {% endif %}
98
67
  </td>
99
68
  <td class="px-6 py-4 whitespace-nowrap text-sm text-font-subtle-light dark:text-font-subtle-dark">
@@ -1,68 +1,4 @@
1
1
  {% load unfold %}
2
2
 
3
- <!-- Modern Statistics Cards Grid -->
4
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8 w-full">
5
- {% for card in cards %}
6
- <div class="bg-white dark:bg-base-900 rounded-xl shadow-sm hover:shadow-md transition-all duration-300 border border-base-200 dark:border-base-700 overflow-hidden group">
7
- <div class="p-5">
8
- <div class="flex items-start justify-between">
9
- <div class="flex-1">
10
- <!-- Title -->
11
- <div class="text-xs font-semibold text-font-subtle-light dark:text-font-subtle-dark uppercase tracking-wider mb-2">
12
- {{ card.title }}
13
- </div>
14
-
15
- <!-- Value -->
16
- <div class="text-2xl font-bold text-font-important-light dark:text-font-important-dark mb-1">
17
- {{ card.value }}
18
- </div>
19
-
20
- <!-- Change indicator -->
21
- {% if card.change %}
22
- <div class="flex items-center">
23
- <div class="flex items-center px-2 py-1 rounded-full text-xs font-medium
24
- {% if card.change_type == 'positive' %}bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400
25
- {% elif card.change_type == 'negative' %}bg-red-100 dark:bg-red-900/20 text-red-600 dark:text-red-400
26
- {% else %}bg-base-100 dark:bg-base-800 text-font-default-light dark:text-font-default-dark{% endif %}">
27
-
28
- <span class="material-icons text-xs mr-1">
29
- {% if card.change_type == 'positive' %}arrow_upward
30
- {% elif card.change_type == 'negative' %}arrow_downward
31
- {% else %}remove{% endif %}
32
- </span>
33
- {{ card.change }}
34
- </div>
35
- </div>
36
- {% endif %}
37
-
38
- <!-- Description -->
39
- {% if card.description %}
40
- <div class="text-xs text-font-subtle-light dark:text-font-subtle-dark mt-1">
41
- {{ card.description }}
42
- </div>
43
- {% endif %}
44
- </div>
45
-
46
- <!-- Icon -->
47
- <div class="flex-shrink-0 ml-3">
48
- <div class="w-10 h-10 flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
49
- <span class="material-icons text-2xl
50
- {% if card.change_type == 'positive' %}text-green-600 dark:text-green-400
51
- {% elif card.change_type == 'negative' %}text-red-600 dark:text-red-400
52
- {% else %}text-primary-600 dark:text-primary-400{% endif %}">
53
- {{ card.icon }}
54
- </span>
55
- </div>
56
- </div>
57
- </div>
58
- </div>
59
-
60
- <!-- Subtle bottom accent -->
61
- <div class="h-1 w-full
62
- {% if card.change_type == 'positive' %}bg-gradient-to-r from-green-400 to-green-600
63
- {% elif card.change_type == 'negative' %}bg-gradient-to-r from-red-400 to-red-600
64
- {% else %}bg-gradient-to-r from-primary-400 to-primary-600{% endif %}">
65
- </div>
66
- </div>
67
- {% endfor %}
68
- </div>
3
+ <!-- Modern Statistics Cards Grid using reusable component -->
4
+ {% include 'admin/components/stats_grid.html' with stats=cards cols=4 gap=4 class="mb-8 w-full" %}
@@ -1,72 +1,22 @@
1
1
  {% load unfold %}
2
2
 
3
- <!-- System Health Grid with semantic colors -->
3
+ <!-- System Health Grid using reusable components -->
4
4
  <div class="mt-8 w-full">
5
- <div class="flex items-center mb-6">
6
- <div class="flex items-center justify-center w-8 h-8 bg-green-100 dark:bg-green-900/20 rounded-lg mr-3">
7
- <span class="material-icons text-green-600 dark:text-green-400 text-lg">health_and_safety</span>
8
- </div>
9
- <h2 class="text-xl font-semibold text-font-important-light dark:text-font-important-dark">
10
- System Health
11
- </h2>
12
- </div>
5
+ {% include 'admin/components/section_header.html' with title='System Health' icon='health_and_safety' icon_color='green' %}
13
6
 
14
7
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 w-full">
15
8
  {% for key, value in system_health.items %}
16
- <div class="bg-white dark:bg-base-900 rounded-lg p-5 border border-base-200 dark:border-base-700 hover:shadow-md transition-shadow duration-200">
17
- <div class="flex items-center justify-between">
18
- <div class="flex items-center space-x-3">
19
- <div class="flex-shrink-0">
20
- {% if key == "database_status" %}
21
- <span class="material-icons text-green-600 dark:text-green-400">storage</span>
22
- {% elif key == "cache_status" %}
23
- <span class="material-icons text-primary-600 dark:text-primary-400">memory</span>
24
- {% elif key == "queue_status" %}
25
- <span class="material-icons text-amber-600 dark:text-amber-400">queue</span>
26
- {% elif key == "storage_status" %}
27
- <span class="material-icons text-blue-600 dark:text-blue-400">folder</span>
28
- {% else %}
29
- <span class="material-icons text-font-subtle-light dark:text-font-subtle-dark">info</span>
30
- {% endif %}
31
- </div>
32
- <div>
33
- <div class="text-sm font-medium text-font-default-light dark:text-font-default-dark">
34
- {% if key == "database_status" %}Database
35
- {% elif key == "cache_status" %}Cache
36
- {% elif key == "queue_status" %}Queue
37
- {% elif key == "storage_status" %}Storage
38
- {% else %}{{ key|title }}{% endif %}
39
- </div>
40
- <div class="text-xs text-font-subtle-light dark:text-font-subtle-dark mt-1">
41
- {% if key == "database_status" %}Connection & queries
42
- {% elif key == "cache_status" %}Redis & memory
43
- {% elif key == "queue_status" %}Background jobs
44
- {% elif key == "storage_status" %}Disk & files
45
- {% else %}System component{% endif %}
46
- </div>
47
- </div>
48
- </div>
49
-
50
- <div class="flex-shrink-0">
51
- {% if value == 'healthy' or value == 'ok' or value == 'connected' %}
52
- <span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400">
53
- <span class="material-icons text-xs mr-1">check_circle</span>
54
- {{ value|title }}
55
- </span>
56
- {% elif value == 'warning' or value == 'degraded' %}
57
- <span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold bg-amber-100 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400">
58
- <span class="material-icons text-xs mr-1">warning</span>
59
- {{ value|title }}
60
- </span>
61
- {% else %}
62
- <span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold bg-red-100 dark:bg-red-900/20 text-red-600 dark:text-red-400">
63
- <span class="material-icons text-xs mr-1">error</span>
64
- {{ value|title }}
65
- </span>
66
- {% endif %}
67
- </div>
68
- </div>
69
- </div>
9
+ {% if key == "database_status" %}
10
+ {% include 'admin/components/metric_card.html' with title='Database' description='Connection & queries' icon='storage' status=value|yesno:'healthy,error' status_text=value|title %}
11
+ {% elif key == "cache_status" %}
12
+ {% include 'admin/components/metric_card.html' with title='Cache' description='Redis & memory' icon='memory' status=value|yesno:'healthy,error' status_text=value|title %}
13
+ {% elif key == "queue_status" %}
14
+ {% include 'admin/components/metric_card.html' with title='Queue' description='Background jobs' icon='queue' status=value|yesno:'healthy,error' status_text=value|title %}
15
+ {% elif key == "storage_status" %}
16
+ {% include 'admin/components/metric_card.html' with title='Storage' description='Disk & files' icon='folder' status=value|yesno:'healthy,error' status_text=value|title %}
17
+ {% else %}
18
+ {% include 'admin/components/metric_card.html' with title=key|title description='System component' icon='info' status=value|yesno:'healthy,error' status_text=value|title %}
19
+ {% endif %}
70
20
  {% endfor %}
71
21
  </div>
72
22
  </div>