django-cfg 1.4.75__py3-none-any.whl → 1.4.77__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/agents/__init__.py +1 -1
- django_cfg/apps/agents/integration/registry.py +1 -1
- django_cfg/apps/agents/patterns/content_agents.py +1 -1
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +1 -1
- django_cfg/apps/centrifugo/views/dashboard.py +13 -0
- django_cfg/apps/centrifugo/views/testing_api.py +74 -15
- django_cfg/apps/tasks/views/dashboard.py +4 -4
- django_cfg/core/generation/integration_generators/api.py +5 -2
- django_cfg/management/commands/check_endpoints.py +1 -1
- django_cfg/modules/django_client/core/generator/python/models_generator.py +6 -6
- django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +0 -2
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +0 -1
- django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +2 -1
- django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +7 -1
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +2 -2
- django_cfg/modules/django_unfold/callbacks/main.py +27 -25
- django_cfg/pyproject.toml +1 -1
- django_cfg/static/admin/css/constance.css +44 -0
- django_cfg/static/admin/css/dashboard.css +6 -170
- django_cfg/static/admin/css/layout.css +21 -0
- django_cfg/static/admin/css/tabs.css +95 -0
- django_cfg/static/admin/css/theme.css +74 -0
- django_cfg/static/admin/js/alpine/activity-tracker.js +55 -0
- django_cfg/static/admin/js/alpine/chart.js +101 -0
- django_cfg/static/admin/js/alpine/command-modal.js +159 -0
- django_cfg/static/admin/js/alpine/commands-panel.js +139 -0
- django_cfg/static/admin/js/alpine/commands-section.js +260 -0
- django_cfg/static/admin/js/alpine/dashboard-tabs.js +46 -0
- django_cfg/static/admin/js/alpine/system-metrics.js +20 -0
- django_cfg/static/admin/js/alpine/toggle-section.js +28 -0
- django_cfg/static/admin/js/utils.js +60 -0
- django_cfg/templates/admin/components/modal.html +1 -1
- django_cfg/templates/admin/constance/change_list.html +3 -42
- django_cfg/templates/admin/index.html +0 -8
- django_cfg/templates/admin/layouts/base_dashboard.html +4 -2
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +104 -502
- django_cfg/templates/admin/sections/commands_section.html +374 -451
- django_cfg/templates/admin/sections/documentation_section.html +13 -33
- django_cfg/templates/admin/snippets/components/activity_tracker.html +27 -49
- django_cfg/templates/admin/snippets/components/charts_section.html +8 -74
- django_cfg/templates/admin/snippets/components/django_commands.html +94 -181
- django_cfg/templates/admin/snippets/components/system_metrics.html +18 -10
- django_cfg/templates/admin/snippets/tabs/app_stats_tab.html +2 -2
- django_cfg/templates/admin/snippets/tabs/commands_tab.html +48 -0
- django_cfg/templates/admin/snippets/tabs/documentation_tab.html +1 -190
- django_cfg/templates/admin/snippets/tabs/overview_tab.html +1 -1
- {django_cfg-1.4.75.dist-info → django_cfg-1.4.77.dist-info}/METADATA +1 -1
- {django_cfg-1.4.75.dist-info → django_cfg-1.4.77.dist-info}/RECORD +52 -44
- django_cfg/static/admin/js/commands.js +0 -171
- django_cfg/static/admin/js/dashboard.js +0 -126
- django_cfg/templates/admin/components/management_commands.js +0 -375
- django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +0 -322
- django_cfg/templates/admin/snippets/components/recent_activity.html +0 -35
- {django_cfg-1.4.75.dist-info → django_cfg-1.4.77.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.75.dist-info → django_cfg-1.4.77.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.75.dist-info → django_cfg-1.4.77.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
# Chart.js Integration Guide
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This guide documents the Chart.js integration in the Django CFG dashboard, including key insights, best practices, and solutions to common issues.
|
|
6
|
-
|
|
7
|
-
## Architecture
|
|
8
|
-
|
|
9
|
-
### Data Flow
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
Python (callbacks/charts.py)
|
|
13
|
-
→ Pydantic Models (ChartData, ChartDataset)
|
|
14
|
-
→ JSON Serialization (.model_dump())
|
|
15
|
-
→ Django Template (|safe filter)
|
|
16
|
-
→ JavaScript (Chart.js)
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### File Structure
|
|
20
|
-
|
|
21
|
-
- **Backend**: `/django_cfg/modules/django_unfold/callbacks/charts.py` - Chart data generation
|
|
22
|
-
- **Models**: `/django_cfg/modules/django_unfold/models/charts.py` - Pydantic data models
|
|
23
|
-
- **Template**: `/django_cfg/templates/admin/snippets/components/charts_section.html` - Chart rendering
|
|
24
|
-
|
|
25
|
-
## Key Implementation Details
|
|
26
|
-
|
|
27
|
-
### 1. Container Height - CRITICAL
|
|
28
|
-
|
|
29
|
-
**❌ WRONG - Infinite Height Growth:**
|
|
30
|
-
```html
|
|
31
|
-
<canvas id="myChart" height="300"></canvas>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**✅ CORRECT - Fixed Container:**
|
|
35
|
-
```html
|
|
36
|
-
<div class="relative h-[300px]">
|
|
37
|
-
<canvas id="myChart"></canvas>
|
|
38
|
-
</div>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**Why:** Chart.js with `responsive: true` + `maintainAspectRatio: false` needs a fixed-height parent container. Without it, the canvas grows infinitely as Chart.js tries to maintain responsiveness.
|
|
42
|
-
|
|
43
|
-
### 2. Data Format
|
|
44
|
-
|
|
45
|
-
Chart.js expects this structure:
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
{
|
|
49
|
-
type: 'line', // or 'bar', 'pie', etc.
|
|
50
|
-
data: {
|
|
51
|
-
labels: ['Day 1', 'Day 2', ...],
|
|
52
|
-
datasets: [{
|
|
53
|
-
label: 'Dataset Name',
|
|
54
|
-
data: [10, 20, 30, ...],
|
|
55
|
-
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
|
56
|
-
borderColor: 'rgb(59, 130, 246)',
|
|
57
|
-
tension: 0.4 // for line charts
|
|
58
|
-
}]
|
|
59
|
-
},
|
|
60
|
-
options: { ... }
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
**Our Implementation:**
|
|
65
|
-
```javascript
|
|
66
|
-
new Chart(ctx, {
|
|
67
|
-
type: 'line',
|
|
68
|
-
data: chartData, // chartData = {labels: [...], datasets: [...]}
|
|
69
|
-
options: { ... }
|
|
70
|
-
});
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 3. Python to JavaScript Bridge
|
|
74
|
-
|
|
75
|
-
**Backend (charts.py):**
|
|
76
|
-
```python
|
|
77
|
-
from .models.charts import ChartData, ChartDataset
|
|
78
|
-
|
|
79
|
-
def get_user_registration_chart_data(self) -> Dict[str, Any]:
|
|
80
|
-
chart_data = ChartData(
|
|
81
|
-
labels=["09/26", "09/27", ...],
|
|
82
|
-
datasets=[
|
|
83
|
-
ChartDataset(
|
|
84
|
-
label="New Users",
|
|
85
|
-
data=[2, 5, 3, ...],
|
|
86
|
-
backgroundColor="rgba(59, 130, 246, 0.1)",
|
|
87
|
-
borderColor="rgb(59, 130, 246)",
|
|
88
|
-
tension=0.4
|
|
89
|
-
)
|
|
90
|
-
]
|
|
91
|
-
)
|
|
92
|
-
return chart_data.model_dump() # Converts Pydantic to dict
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**Template:**
|
|
96
|
-
```html
|
|
97
|
-
<!-- Serialize to JSON for JavaScript -->
|
|
98
|
-
"charts": {
|
|
99
|
-
"user_registrations_json": json.dumps(self.get_user_registration_chart_data()),
|
|
100
|
-
"user_registrations": self.get_user_registration_chart_data(),
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**HTML/JavaScript:**
|
|
105
|
-
```html
|
|
106
|
-
<script>
|
|
107
|
-
const chartData = {{ charts.user_registrations_json|safe }};
|
|
108
|
-
new Chart(ctx, {
|
|
109
|
-
type: 'line',
|
|
110
|
-
data: chartData,
|
|
111
|
-
options: { ... }
|
|
112
|
-
});
|
|
113
|
-
</script>
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### 4. Chart.js Configuration Best Practices
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
{
|
|
120
|
-
type: 'line', // or 'bar'
|
|
121
|
-
data: chartData,
|
|
122
|
-
options: {
|
|
123
|
-
responsive: true, // Chart resizes with container
|
|
124
|
-
maintainAspectRatio: false, // Don't maintain aspect ratio
|
|
125
|
-
plugins: {
|
|
126
|
-
legend: {
|
|
127
|
-
display: true,
|
|
128
|
-
position: 'top'
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
scales: {
|
|
132
|
-
y: {
|
|
133
|
-
beginAtZero: true, // Start Y axis at 0
|
|
134
|
-
ticks: {
|
|
135
|
-
precision: 0 // Show integers only (no decimals)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Common Issues & Solutions
|
|
144
|
-
|
|
145
|
-
### Issue 1: Charts Not Displaying
|
|
146
|
-
|
|
147
|
-
**Symptoms:** Canvas element exists but no chart visible
|
|
148
|
-
|
|
149
|
-
**Debug Checklist:**
|
|
150
|
-
```javascript
|
|
151
|
-
console.log('Chart.js loaded:', typeof Chart !== 'undefined');
|
|
152
|
-
console.log('Canvas element:', document.getElementById('myChart'));
|
|
153
|
-
console.log('Chart data:', chartData);
|
|
154
|
-
console.log('Data has labels:', 'labels' in chartData);
|
|
155
|
-
console.log('Data has datasets:', 'datasets' in chartData);
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
**Common Causes:**
|
|
159
|
-
1. Chart.js library not loaded
|
|
160
|
-
2. Canvas ID mismatch
|
|
161
|
-
3. Data format incorrect
|
|
162
|
-
4. DOMContentLoaded not fired yet
|
|
163
|
-
|
|
164
|
-
### Issue 2: Infinite Height Growth
|
|
165
|
-
|
|
166
|
-
**Symptoms:** Chart keeps expanding vertically, page becomes very tall
|
|
167
|
-
|
|
168
|
-
**Solution:** Wrap canvas in fixed-height container (see section 1 above)
|
|
169
|
-
|
|
170
|
-
### Issue 3: Data Not Updating
|
|
171
|
-
|
|
172
|
-
**Symptoms:** Chart shows old data after refresh
|
|
173
|
-
|
|
174
|
-
**Solution:** Ensure Chart.js recreates instead of updates:
|
|
175
|
-
```javascript
|
|
176
|
-
// Destroy existing chart first
|
|
177
|
-
if (window.myChart) {
|
|
178
|
-
window.myChart.destroy();
|
|
179
|
-
}
|
|
180
|
-
window.myChart = new Chart(ctx, config);
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Issue 4: Dark Mode Colors
|
|
184
|
-
|
|
185
|
-
**Best Practices:**
|
|
186
|
-
```python
|
|
187
|
-
ChartDataset(
|
|
188
|
-
backgroundColor="rgba(59, 130, 246, 0.1)", # Light with transparency
|
|
189
|
-
borderColor="rgb(59, 130, 246)", # Solid color
|
|
190
|
-
# Use theme-aware colors that work in both light/dark modes
|
|
191
|
-
)
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## Template Integration
|
|
195
|
-
|
|
196
|
-
### Complete Working Example
|
|
197
|
-
|
|
198
|
-
```html
|
|
199
|
-
{% if charts.user_registrations %}
|
|
200
|
-
<div class="relative h-[300px]">
|
|
201
|
-
<canvas id="userRegistrationsChart"></canvas>
|
|
202
|
-
</div>
|
|
203
|
-
<script>
|
|
204
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
205
|
-
const ctx = document.getElementById('userRegistrationsChart');
|
|
206
|
-
const chartData = {{ charts.user_registrations_json|safe }};
|
|
207
|
-
|
|
208
|
-
if (ctx && typeof Chart !== 'undefined') {
|
|
209
|
-
try {
|
|
210
|
-
new Chart(ctx, {
|
|
211
|
-
type: 'line',
|
|
212
|
-
data: chartData,
|
|
213
|
-
options: {
|
|
214
|
-
responsive: true,
|
|
215
|
-
maintainAspectRatio: false,
|
|
216
|
-
plugins: {
|
|
217
|
-
legend: {
|
|
218
|
-
display: true,
|
|
219
|
-
position: 'top'
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
scales: {
|
|
223
|
-
y: {
|
|
224
|
-
beginAtZero: true,
|
|
225
|
-
ticks: {
|
|
226
|
-
precision: 0
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
} catch (error) {
|
|
233
|
-
console.error('Error creating chart:', error);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
</script>
|
|
238
|
-
{% else %}
|
|
239
|
-
<div class="h-[300px] flex items-center justify-center">
|
|
240
|
-
<p class="text-gray-500">No chart data available</p>
|
|
241
|
-
</div>
|
|
242
|
-
{% endif %}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Testing Chart Integration
|
|
246
|
-
|
|
247
|
-
### 1. Verify Chart.js Load
|
|
248
|
-
|
|
249
|
-
```javascript
|
|
250
|
-
console.log('Chart.js version:', Chart.version); // Should show: 4.4.0
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### 2. Check Data Structure
|
|
254
|
-
|
|
255
|
-
```python
|
|
256
|
-
# In callbacks/charts.py
|
|
257
|
-
chart_data = self.get_user_registration_chart_data()
|
|
258
|
-
print(f"Labels: {chart_data['labels']}")
|
|
259
|
-
print(f"Dataset count: {len(chart_data['datasets'])}")
|
|
260
|
-
print(f"Data points: {chart_data['datasets'][0]['data']}")
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### 3. Template Debugging
|
|
264
|
-
|
|
265
|
-
```html
|
|
266
|
-
<!-- Add temporary debug output -->
|
|
267
|
-
<pre>{{ charts.user_registrations|pprint }}</pre>
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## Performance Considerations
|
|
271
|
-
|
|
272
|
-
1. **Limit Data Points**: Keep chart data to reasonable size (e.g., 7-90 days max)
|
|
273
|
-
2. **Lazy Loading**: Load charts only when tab/section is visible
|
|
274
|
-
3. **Caching**: Cache chart data in backend if queries are expensive
|
|
275
|
-
4. **Animation**: Disable animations for large datasets:
|
|
276
|
-
```javascript
|
|
277
|
-
options: {
|
|
278
|
-
animation: false // or { duration: 0 }
|
|
279
|
-
}
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## Future Enhancements
|
|
283
|
-
|
|
284
|
-
### 1. Interactive Features
|
|
285
|
-
- Click to drill down
|
|
286
|
-
- Hover tooltips with detailed info
|
|
287
|
-
- Date range picker integration
|
|
288
|
-
|
|
289
|
-
### 2. Additional Chart Types
|
|
290
|
-
- Pie/Doughnut for distribution
|
|
291
|
-
- Mixed charts (line + bar)
|
|
292
|
-
- Area charts for cumulative data
|
|
293
|
-
|
|
294
|
-
### 3. Export Functionality
|
|
295
|
-
- Download as PNG/SVG
|
|
296
|
-
- Export data as CSV
|
|
297
|
-
- Share chart snapshots
|
|
298
|
-
|
|
299
|
-
## Troubleshooting Reference
|
|
300
|
-
|
|
301
|
-
| Symptom | Likely Cause | Solution |
|
|
302
|
-
|---------|--------------|----------|
|
|
303
|
-
| Chart not visible | No fixed-height container | Add `h-[300px]` to parent div |
|
|
304
|
-
| Infinite scrolling | Canvas height attribute set | Remove `height="300"` from canvas |
|
|
305
|
-
| No data | Backend not providing data | Check callback method |
|
|
306
|
-
| Wrong data | Cache issue | Clear browser cache |
|
|
307
|
-
| Colors don't match theme | Hardcoded colors | Use CSS variables or theme-aware colors |
|
|
308
|
-
| Chart flickers | Multiple DOMContentLoaded listeners | Ensure single initialization |
|
|
309
|
-
|
|
310
|
-
## References
|
|
311
|
-
|
|
312
|
-
- [Chart.js Documentation](https://www.chartjs.org/docs/latest/)
|
|
313
|
-
- [Chart.js Examples](https://www.chartjs.org/docs/latest/samples/)
|
|
314
|
-
- [Tailwind CSS Height Utilities](https://tailwindcss.com/docs/height)
|
|
315
|
-
- Pydantic Models: `/django_cfg/modules/django_unfold/models/charts.py`
|
|
316
|
-
- Chart Callbacks: `/django_cfg/modules/django_unfold/callbacks/charts.py`
|
|
317
|
-
|
|
318
|
-
---
|
|
319
|
-
|
|
320
|
-
**Last Updated:** 2025-10-03
|
|
321
|
-
**Chart.js Version:** 4.4.0
|
|
322
|
-
**Django Version:** 5.x
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{% load unfold %}
|
|
2
|
-
|
|
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>
|
|
24
|
-
</div>
|
|
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>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
{% endif %}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|