django-cfg 1.1.82__py3-none-any.whl → 1.2.0__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.
- django_cfg/__init__.py +20 -448
- django_cfg/apps/accounts/README.md +3 -3
- django_cfg/apps/accounts/admin/__init__.py +0 -2
- django_cfg/apps/accounts/admin/activity.py +2 -9
- django_cfg/apps/accounts/admin/filters.py +0 -42
- django_cfg/apps/accounts/admin/inlines.py +8 -8
- django_cfg/apps/accounts/admin/otp.py +5 -5
- django_cfg/apps/accounts/admin/registration_source.py +1 -8
- django_cfg/apps/accounts/admin/user.py +12 -20
- django_cfg/apps/accounts/managers/user_manager.py +2 -129
- django_cfg/apps/accounts/migrations/0006_remove_twilioresponse_otp_secret_and_more.py +46 -0
- django_cfg/apps/accounts/models.py +3 -123
- django_cfg/apps/accounts/serializers/otp.py +40 -44
- django_cfg/apps/accounts/serializers/profile.py +0 -2
- django_cfg/apps/accounts/services/otp_service.py +98 -186
- django_cfg/apps/accounts/signals.py +25 -15
- django_cfg/apps/accounts/utils/auth_email_service.py +84 -0
- django_cfg/apps/accounts/views/otp.py +35 -36
- django_cfg/apps/agents/README.md +129 -0
- django_cfg/apps/agents/__init__.py +68 -0
- django_cfg/apps/agents/admin/__init__.py +17 -0
- django_cfg/apps/agents/admin/execution_admin.py +460 -0
- django_cfg/apps/agents/admin/registry_admin.py +360 -0
- django_cfg/apps/agents/admin/toolsets_admin.py +482 -0
- django_cfg/apps/agents/apps.py +29 -0
- django_cfg/apps/agents/core/__init__.py +20 -0
- django_cfg/apps/agents/core/agent.py +281 -0
- django_cfg/apps/agents/core/dependencies.py +154 -0
- django_cfg/apps/agents/core/exceptions.py +66 -0
- django_cfg/apps/agents/core/models.py +106 -0
- django_cfg/apps/agents/core/orchestrator.py +391 -0
- django_cfg/apps/agents/examples/__init__.py +3 -0
- django_cfg/apps/agents/examples/simple_example.py +161 -0
- django_cfg/apps/agents/integration/__init__.py +14 -0
- django_cfg/apps/agents/integration/middleware.py +80 -0
- django_cfg/apps/agents/integration/registry.py +345 -0
- django_cfg/apps/agents/integration/signals.py +50 -0
- django_cfg/apps/agents/management/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/create_agent.py +365 -0
- django_cfg/apps/agents/management/commands/orchestrator_status.py +191 -0
- django_cfg/apps/agents/managers/__init__.py +23 -0
- django_cfg/apps/agents/managers/execution.py +236 -0
- django_cfg/apps/agents/managers/registry.py +254 -0
- django_cfg/apps/agents/managers/toolsets.py +496 -0
- django_cfg/apps/agents/migrations/0001_initial.py +286 -0
- django_cfg/apps/agents/migrations/__init__.py +5 -0
- django_cfg/apps/agents/models/__init__.py +15 -0
- django_cfg/apps/agents/models/execution.py +215 -0
- django_cfg/apps/agents/models/registry.py +220 -0
- django_cfg/apps/agents/models/toolsets.py +305 -0
- django_cfg/apps/agents/patterns/__init__.py +24 -0
- django_cfg/apps/agents/patterns/content_agents.py +234 -0
- django_cfg/apps/agents/toolsets/__init__.py +15 -0
- django_cfg/apps/agents/toolsets/cache_toolset.py +285 -0
- django_cfg/apps/agents/toolsets/django_toolset.py +220 -0
- django_cfg/apps/agents/toolsets/file_toolset.py +324 -0
- django_cfg/apps/agents/toolsets/orm_toolset.py +319 -0
- django_cfg/apps/agents/urls.py +46 -0
- django_cfg/apps/knowbase/README.md +150 -0
- django_cfg/apps/knowbase/__init__.py +27 -0
- django_cfg/apps/knowbase/admin/__init__.py +23 -0
- django_cfg/apps/knowbase/admin/archive_admin.py +857 -0
- django_cfg/apps/knowbase/admin/chat_admin.py +386 -0
- django_cfg/apps/knowbase/admin/document_admin.py +650 -0
- django_cfg/apps/knowbase/admin/external_data_admin.py +685 -0
- django_cfg/apps/knowbase/apps.py +81 -0
- django_cfg/apps/knowbase/config/README.md +176 -0
- django_cfg/apps/knowbase/config/__init__.py +51 -0
- django_cfg/apps/knowbase/config/constance_fields.py +186 -0
- django_cfg/apps/knowbase/config/constance_settings.py +200 -0
- django_cfg/apps/knowbase/config/settings.py +444 -0
- django_cfg/apps/knowbase/examples/__init__.py +3 -0
- django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
- django_cfg/apps/knowbase/management/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/knowbase_stats.py +158 -0
- django_cfg/apps/knowbase/management/commands/setup_knowbase.py +59 -0
- django_cfg/apps/knowbase/managers/__init__.py +22 -0
- django_cfg/apps/knowbase/managers/archive.py +426 -0
- django_cfg/apps/knowbase/managers/base.py +32 -0
- django_cfg/apps/knowbase/managers/chat.py +141 -0
- django_cfg/apps/knowbase/managers/document.py +203 -0
- django_cfg/apps/knowbase/managers/external_data.py +471 -0
- django_cfg/apps/knowbase/migrations/0001_initial.py +427 -0
- django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +434 -0
- django_cfg/apps/knowbase/migrations/__init__.py +5 -0
- django_cfg/apps/knowbase/mixins/__init__.py +15 -0
- django_cfg/apps/knowbase/mixins/config.py +108 -0
- django_cfg/apps/knowbase/mixins/creator.py +81 -0
- django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
- django_cfg/apps/knowbase/mixins/external_data_mixin.py +813 -0
- django_cfg/apps/knowbase/mixins/service.py +362 -0
- django_cfg/apps/knowbase/models/__init__.py +41 -0
- django_cfg/apps/knowbase/models/archive.py +599 -0
- django_cfg/apps/knowbase/models/base.py +58 -0
- django_cfg/apps/knowbase/models/chat.py +157 -0
- django_cfg/apps/knowbase/models/document.py +267 -0
- django_cfg/apps/knowbase/models/external_data.py +376 -0
- django_cfg/apps/knowbase/serializers/__init__.py +68 -0
- django_cfg/apps/knowbase/serializers/archive_serializers.py +386 -0
- django_cfg/apps/knowbase/serializers/chat_serializers.py +137 -0
- django_cfg/apps/knowbase/serializers/document_serializers.py +94 -0
- django_cfg/apps/knowbase/serializers/external_data_serializers.py +256 -0
- django_cfg/apps/knowbase/serializers/public_serializers.py +74 -0
- django_cfg/apps/knowbase/services/__init__.py +40 -0
- django_cfg/apps/knowbase/services/archive/__init__.py +42 -0
- django_cfg/apps/knowbase/services/archive/archive_service.py +541 -0
- django_cfg/apps/knowbase/services/archive/chunking_service.py +791 -0
- django_cfg/apps/knowbase/services/archive/exceptions.py +52 -0
- django_cfg/apps/knowbase/services/archive/extraction_service.py +508 -0
- django_cfg/apps/knowbase/services/archive/vectorization_service.py +362 -0
- django_cfg/apps/knowbase/services/base.py +53 -0
- django_cfg/apps/knowbase/services/chat_service.py +239 -0
- django_cfg/apps/knowbase/services/document_service.py +144 -0
- django_cfg/apps/knowbase/services/embedding/__init__.py +43 -0
- django_cfg/apps/knowbase/services/embedding/async_processor.py +244 -0
- django_cfg/apps/knowbase/services/embedding/batch_processor.py +250 -0
- django_cfg/apps/knowbase/services/embedding/batch_result.py +61 -0
- django_cfg/apps/knowbase/services/embedding/models.py +229 -0
- django_cfg/apps/knowbase/services/embedding/processors.py +148 -0
- django_cfg/apps/knowbase/services/embedding/utils.py +176 -0
- django_cfg/apps/knowbase/services/prompt_builder.py +191 -0
- django_cfg/apps/knowbase/services/search_service.py +293 -0
- django_cfg/apps/knowbase/signals/__init__.py +21 -0
- django_cfg/apps/knowbase/signals/archive_signals.py +211 -0
- django_cfg/apps/knowbase/signals/chat_signals.py +37 -0
- django_cfg/apps/knowbase/signals/document_signals.py +143 -0
- django_cfg/apps/knowbase/signals/external_data_signals.py +157 -0
- django_cfg/apps/knowbase/tasks/__init__.py +39 -0
- django_cfg/apps/knowbase/tasks/archive_tasks.py +316 -0
- django_cfg/apps/knowbase/tasks/document_processing.py +341 -0
- django_cfg/apps/knowbase/tasks/external_data_tasks.py +341 -0
- django_cfg/apps/knowbase/tasks/maintenance.py +195 -0
- django_cfg/apps/knowbase/urls.py +43 -0
- django_cfg/apps/knowbase/utils/__init__.py +12 -0
- django_cfg/apps/knowbase/utils/chunk_settings.py +261 -0
- django_cfg/apps/knowbase/utils/text_processing.py +375 -0
- django_cfg/apps/knowbase/utils/validation.py +99 -0
- django_cfg/apps/knowbase/views/__init__.py +28 -0
- django_cfg/apps/knowbase/views/archive_views.py +469 -0
- django_cfg/apps/knowbase/views/base.py +49 -0
- django_cfg/apps/knowbase/views/chat_views.py +181 -0
- django_cfg/apps/knowbase/views/document_views.py +183 -0
- django_cfg/apps/knowbase/views/public_views.py +129 -0
- django_cfg/apps/leads/admin.py +70 -0
- django_cfg/apps/newsletter/admin.py +234 -0
- django_cfg/apps/newsletter/admin_filters.py +124 -0
- django_cfg/apps/support/admin.py +196 -0
- django_cfg/apps/support/admin_filters.py +71 -0
- django_cfg/apps/support/templates/support/chat/ticket_chat.html +1 -1
- django_cfg/apps/urls.py +5 -4
- django_cfg/cli/README.md +1 -1
- django_cfg/cli/commands/create_project.py +2 -2
- django_cfg/cli/commands/info.py +1 -1
- django_cfg/config.py +44 -0
- django_cfg/core/config.py +29 -82
- django_cfg/core/environment.py +1 -1
- django_cfg/core/generation.py +19 -107
- django_cfg/{integration.py → core/integration.py} +18 -16
- django_cfg/core/validation.py +1 -1
- django_cfg/management/__init__.py +1 -1
- django_cfg/management/commands/__init__.py +1 -1
- django_cfg/management/commands/auto_generate.py +482 -0
- django_cfg/management/commands/migrator.py +19 -101
- django_cfg/management/commands/test_email.py +1 -1
- django_cfg/middleware/README.md +0 -158
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/api.py +145 -0
- django_cfg/models/base.py +287 -0
- django_cfg/models/cache.py +4 -4
- django_cfg/models/constance.py +25 -88
- django_cfg/models/database.py +9 -9
- django_cfg/models/drf.py +3 -36
- django_cfg/models/email.py +163 -0
- django_cfg/models/environment.py +276 -0
- django_cfg/models/limits.py +1 -1
- django_cfg/models/logging.py +366 -0
- django_cfg/models/revolution.py +41 -2
- django_cfg/models/security.py +125 -0
- django_cfg/models/services.py +1 -1
- django_cfg/modules/__init__.py +2 -56
- django_cfg/modules/base.py +78 -52
- django_cfg/modules/django_currency/service.py +2 -2
- django_cfg/modules/django_email.py +2 -2
- django_cfg/modules/django_health.py +267 -0
- django_cfg/modules/django_llm/llm/client.py +79 -17
- django_cfg/modules/django_llm/translator/translator.py +2 -2
- django_cfg/modules/django_logger.py +2 -2
- django_cfg/modules/django_ngrok.py +2 -2
- django_cfg/modules/django_tasks.py +68 -3
- django_cfg/modules/django_telegram.py +3 -3
- django_cfg/modules/django_twilio/sendgrid_service.py +2 -2
- django_cfg/modules/django_twilio/service.py +2 -2
- django_cfg/modules/django_twilio/simple_service.py +2 -2
- django_cfg/modules/django_twilio/twilio_service.py +2 -2
- django_cfg/modules/django_unfold/__init__.py +69 -0
- django_cfg/modules/{unfold → django_unfold}/callbacks.py +23 -22
- django_cfg/modules/django_unfold/dashboard.py +278 -0
- django_cfg/modules/django_unfold/icons/README.md +145 -0
- django_cfg/modules/django_unfold/icons/__init__.py +12 -0
- django_cfg/modules/django_unfold/icons/constants.py +2851 -0
- django_cfg/modules/django_unfold/icons/generate_icons.py +486 -0
- django_cfg/modules/django_unfold/models/__init__.py +42 -0
- django_cfg/modules/django_unfold/models/config.py +601 -0
- django_cfg/modules/django_unfold/models/dashboard.py +206 -0
- django_cfg/modules/django_unfold/models/dropdown.py +40 -0
- django_cfg/modules/django_unfold/models/navigation.py +73 -0
- django_cfg/modules/django_unfold/models/tabs.py +25 -0
- django_cfg/modules/{unfold → django_unfold}/system_monitor.py +2 -2
- django_cfg/modules/django_unfold/utils.py +140 -0
- django_cfg/registry/__init__.py +23 -0
- django_cfg/registry/core.py +61 -0
- django_cfg/registry/exceptions.py +11 -0
- django_cfg/registry/modules.py +12 -0
- django_cfg/registry/services.py +26 -0
- django_cfg/registry/third_party.py +52 -0
- django_cfg/routing/__init__.py +19 -0
- django_cfg/routing/callbacks.py +198 -0
- django_cfg/routing/routers.py +48 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +8 -9
- django_cfg/templatetags/__init__.py +0 -0
- django_cfg/templatetags/django_cfg.py +33 -0
- django_cfg/urls.py +33 -0
- django_cfg/utils/path_resolution.py +1 -1
- django_cfg/utils/smart_defaults.py +7 -61
- django_cfg/utils/toolkit.py +663 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/METADATA +83 -86
- django_cfg-1.2.0.dist-info/RECORD +441 -0
- django_cfg/archive/django_sample.zip +0 -0
- django_cfg/models/unfold.py +0 -271
- django_cfg/modules/unfold/__init__.py +0 -29
- django_cfg/modules/unfold/dashboard.py +0 -318
- django_cfg/pyproject.toml +0 -370
- django_cfg/routers.py +0 -83
- django_cfg-1.1.82.dist-info/RECORD +0 -278
- /django_cfg/{exceptions.py → core/exceptions.py} +0 -0
- /django_cfg/modules/{unfold → django_unfold}/models.py +0 -0
- /django_cfg/modules/{unfold → django_unfold}/tailwind.py +0 -0
- /django_cfg/{version_check.py → utils/version_check.py} +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/WHEEL +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
"""
|
2
|
+
Django CFG Unfold Module
|
3
|
+
|
4
|
+
Provides complete Unfold admin interface integration with dashboard,
|
5
|
+
navigation, theming, and callback support.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .dashboard import DashboardManager, get_dashboard_manager
|
9
|
+
from .callbacks import UnfoldCallbacks
|
10
|
+
from .system_monitor import SystemMonitor
|
11
|
+
from .tailwind import get_unfold_colors, get_css_variables
|
12
|
+
from .models import *
|
13
|
+
|
14
|
+
# Lazy initialization functions to avoid circular imports
|
15
|
+
def get_system_monitor() -> SystemMonitor:
|
16
|
+
"""Get the global system monitor instance."""
|
17
|
+
global _system_monitor
|
18
|
+
if '_system_monitor' not in globals():
|
19
|
+
globals()['_system_monitor'] = SystemMonitor()
|
20
|
+
return globals()['_system_monitor']
|
21
|
+
|
22
|
+
def get_unfold_callbacks() -> UnfoldCallbacks:
|
23
|
+
"""Get the global unfold callbacks instance."""
|
24
|
+
global _unfold_callbacks
|
25
|
+
if '_unfold_callbacks' not in globals():
|
26
|
+
globals()['_unfold_callbacks'] = UnfoldCallbacks()
|
27
|
+
return globals()['_unfold_callbacks']
|
28
|
+
|
29
|
+
# Export main components
|
30
|
+
__all__ = [
|
31
|
+
'DashboardManager',
|
32
|
+
'get_dashboard_manager',
|
33
|
+
'UnfoldCallbacks',
|
34
|
+
'get_unfold_callbacks',
|
35
|
+
'SystemMonitor',
|
36
|
+
'get_system_monitor',
|
37
|
+
'get_unfold_colors',
|
38
|
+
'get_css_variables',
|
39
|
+
# Models
|
40
|
+
'UnfoldConfig',
|
41
|
+
'UnfoldTheme',
|
42
|
+
'UnfoldColors',
|
43
|
+
'UnfoldSidebar',
|
44
|
+
'UnfoldThemeConfig',
|
45
|
+
'UnfoldDashboardConfig',
|
46
|
+
'NavigationItem',
|
47
|
+
'NavigationSection',
|
48
|
+
'NavigationItemType',
|
49
|
+
'SiteDropdownItem',
|
50
|
+
'StatCard',
|
51
|
+
'SystemHealthItem',
|
52
|
+
'QuickAction',
|
53
|
+
'DashboardWidget',
|
54
|
+
'DashboardData',
|
55
|
+
'ChartDataset',
|
56
|
+
'ChartData',
|
57
|
+
'TabConfiguration',
|
58
|
+
'TabItem',
|
59
|
+
]
|
60
|
+
|
61
|
+
# Version info
|
62
|
+
__version__ = '1.0.0'
|
63
|
+
__author__ = 'Django CFG Team'
|
64
|
+
__email__ = 'team@djangocfg.com'
|
65
|
+
|
66
|
+
# Module metadata
|
67
|
+
__title__ = 'Django CFG Unfold'
|
68
|
+
__description__ = 'Complete Unfold admin interface integration'
|
69
|
+
__url__ = 'https://github.com/djangocfg/django-cfg'
|
@@ -21,8 +21,9 @@ from django.db import connection
|
|
21
21
|
from django.core.cache import cache
|
22
22
|
from django.apps import apps
|
23
23
|
|
24
|
-
from ..base import
|
25
|
-
from .models import DashboardData, StatCard, SystemHealthItem, QuickAction
|
24
|
+
from ..base import BaseCfgModule
|
25
|
+
from .models.dashboard import DashboardData, StatCard, SystemHealthItem, QuickAction
|
26
|
+
from .icons import Icons
|
26
27
|
|
27
28
|
logger = logging.getLogger(__name__)
|
28
29
|
|
@@ -119,7 +120,7 @@ def get_user_admin_urls():
|
|
119
120
|
}
|
120
121
|
|
121
122
|
|
122
|
-
class UnfoldCallbacks(
|
123
|
+
class UnfoldCallbacks(BaseCfgModule):
|
123
124
|
"""
|
124
125
|
Base Unfold dashboard callbacks with full system monitoring.
|
125
126
|
|
@@ -148,7 +149,7 @@ class UnfoldCallbacks(BaseModule):
|
|
148
149
|
StatCard(
|
149
150
|
title="Total Users",
|
150
151
|
value=f"{total_users:,}",
|
151
|
-
icon=
|
152
|
+
icon=Icons.PEOPLE,
|
152
153
|
change=f"+{new_users_7d}" if new_users_7d > 0 else None,
|
153
154
|
change_type="positive" if new_users_7d > 0 else "neutral",
|
154
155
|
description="Registered users",
|
@@ -156,7 +157,7 @@ class UnfoldCallbacks(BaseModule):
|
|
156
157
|
StatCard(
|
157
158
|
title="Active Users",
|
158
159
|
value=f"{active_users:,}",
|
159
|
-
icon=
|
160
|
+
icon=Icons.PERSON,
|
160
161
|
change=(
|
161
162
|
f"{(active_users/total_users*100):.1f}%"
|
162
163
|
if total_users > 0
|
@@ -170,14 +171,14 @@ class UnfoldCallbacks(BaseModule):
|
|
170
171
|
StatCard(
|
171
172
|
title="New This Week",
|
172
173
|
value=f"{new_users_7d:,}",
|
173
|
-
icon=
|
174
|
+
icon=Icons.PERSON_ADD,
|
174
175
|
change_type="positive" if new_users_7d > 0 else "neutral",
|
175
176
|
description="Last 7 days",
|
176
177
|
),
|
177
178
|
StatCard(
|
178
179
|
title="Staff Members",
|
179
180
|
value=f"{staff_users:,}",
|
180
|
-
icon=
|
181
|
+
icon=Icons.ADMIN_PANEL_SETTINGS,
|
181
182
|
change=(
|
182
183
|
f"{(staff_users/total_users*100):.1f}%" if total_users > 0 else "0%"
|
183
184
|
),
|
@@ -191,7 +192,7 @@ class UnfoldCallbacks(BaseModule):
|
|
191
192
|
StatCard(
|
192
193
|
title="Users",
|
193
194
|
value="N/A",
|
194
|
-
icon=
|
195
|
+
icon=Icons.PEOPLE,
|
195
196
|
description="Data unavailable",
|
196
197
|
)
|
197
198
|
]
|
@@ -316,7 +317,7 @@ class UnfoldCallbacks(BaseModule):
|
|
316
317
|
QuickAction(
|
317
318
|
title="Add User",
|
318
319
|
description="Create new user account",
|
319
|
-
icon=
|
320
|
+
icon=Icons.PERSON_ADD,
|
320
321
|
link=user_admin_urls["add"],
|
321
322
|
color="primary",
|
322
323
|
category="admin",
|
@@ -324,16 +325,16 @@ class UnfoldCallbacks(BaseModule):
|
|
324
325
|
QuickAction(
|
325
326
|
title="Support Tickets",
|
326
327
|
description="Manage support tickets",
|
327
|
-
icon=
|
328
|
+
icon=Icons.SUPPORT_AGENT,
|
328
329
|
link="admin:django_cfg_support_ticket_changelist",
|
329
|
-
color="
|
330
|
+
color="primary",
|
330
331
|
category="support",
|
331
332
|
),
|
332
333
|
QuickAction(
|
333
334
|
title="Health Check",
|
334
335
|
description="System health status",
|
335
|
-
icon=
|
336
|
-
link="
|
336
|
+
icon=Icons.HEALTH_AND_SAFETY,
|
337
|
+
link="/cfg/health/",
|
337
338
|
color="success",
|
338
339
|
category="system",
|
339
340
|
),
|
@@ -382,7 +383,7 @@ class UnfoldCallbacks(BaseModule):
|
|
382
383
|
StatCard(
|
383
384
|
title="Total Tickets",
|
384
385
|
value=f"{total_tickets:,}",
|
385
|
-
icon=
|
386
|
+
icon=Icons.SUPPORT_AGENT,
|
386
387
|
change=f"+{new_tickets_7d}" if new_tickets_7d > 0 else None,
|
387
388
|
change_type="positive" if new_tickets_7d > 0 else "neutral",
|
388
389
|
description="All support tickets",
|
@@ -390,7 +391,7 @@ class UnfoldCallbacks(BaseModule):
|
|
390
391
|
StatCard(
|
391
392
|
title="Open Tickets",
|
392
393
|
value=f"{open_tickets:,}",
|
393
|
-
icon=
|
394
|
+
icon=Icons.PENDING,
|
394
395
|
change=(
|
395
396
|
f"{(open_tickets/total_tickets*100):.1f}%"
|
396
397
|
if total_tickets > 0
|
@@ -406,7 +407,7 @@ class UnfoldCallbacks(BaseModule):
|
|
406
407
|
StatCard(
|
407
408
|
title="Resolved",
|
408
409
|
value=f"{resolved_tickets:,}",
|
409
|
-
icon=
|
410
|
+
icon=Icons.CHECK_CIRCLE,
|
410
411
|
change=(
|
411
412
|
f"{(resolved_tickets/total_tickets*100):.1f}%"
|
412
413
|
if total_tickets > 0
|
@@ -418,7 +419,7 @@ class UnfoldCallbacks(BaseModule):
|
|
418
419
|
StatCard(
|
419
420
|
title="New This Week",
|
420
421
|
value=f"{new_tickets_7d:,}",
|
421
|
-
icon=
|
422
|
+
icon=Icons.NEW_RELEASES,
|
422
423
|
change_type="positive" if new_tickets_7d > 0 else "neutral",
|
423
424
|
description="Last 7 days",
|
424
425
|
),
|
@@ -429,7 +430,7 @@ class UnfoldCallbacks(BaseModule):
|
|
429
430
|
StatCard(
|
430
431
|
title="Support",
|
431
432
|
value="N/A",
|
432
|
-
icon=
|
433
|
+
icon=Icons.SUPPORT_AGENT,
|
433
434
|
description="Data unavailable",
|
434
435
|
)
|
435
436
|
]
|
@@ -707,14 +708,14 @@ class UnfoldCallbacks(BaseModule):
|
|
707
708
|
environment=getattr(settings, "ENVIRONMENT", "development"),
|
708
709
|
)
|
709
710
|
|
710
|
-
# Convert to template context (
|
711
|
-
cards_data = [card.
|
711
|
+
# Convert to template context (using to_dict for Unfold compatibility)
|
712
|
+
cards_data = [card.to_dict() for card in dashboard_data.stat_cards]
|
712
713
|
|
713
714
|
context.update({
|
714
715
|
# Statistics cards
|
715
716
|
"cards": cards_data,
|
716
|
-
"user_stats": [card.
|
717
|
-
"support_stats": [card.
|
717
|
+
"user_stats": [card.to_dict() for card in user_stats],
|
718
|
+
"support_stats": [card.to_dict() for card in support_stats],
|
718
719
|
# System health (convert to dict for template)
|
719
720
|
"system_health": {
|
720
721
|
item.component + "_status": item.status
|
@@ -0,0 +1,278 @@
|
|
1
|
+
"""
|
2
|
+
Dashboard Manager for Django CFG Unfold
|
3
|
+
|
4
|
+
Manages dashboard configuration, widgets, and navigation
|
5
|
+
based on the working configuration from the old version.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import List, Dict, Any, Optional
|
9
|
+
from django.templatetags.static import static
|
10
|
+
from django.urls import reverse_lazy
|
11
|
+
from ..base import BaseCfgModule
|
12
|
+
from .icons import Icons
|
13
|
+
from .models.navigation import NavigationSection, NavigationItem
|
14
|
+
from .models.dashboard import StatCard, StatsCardsWidget
|
15
|
+
|
16
|
+
|
17
|
+
class DashboardManager(BaseCfgModule):
|
18
|
+
"""
|
19
|
+
Dashboard configuration manager for Unfold.
|
20
|
+
|
21
|
+
Based on the working configuration from @old/api__old/api/dashboard/unfold_config.py
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self):
|
25
|
+
"""Initialize dashboard manager."""
|
26
|
+
super().__init__()
|
27
|
+
self.config = self.get_config()
|
28
|
+
|
29
|
+
def _get_default_dropdown_items(self) -> List[Dict[str, Any]]:
|
30
|
+
"""Get default dropdown menu items for Unfold admin (lazy import to avoid circular imports)."""
|
31
|
+
from django_cfg.config import get_default_dropdown_items
|
32
|
+
dropdown_items = get_default_dropdown_items()
|
33
|
+
|
34
|
+
# Convert SiteDropdownItem objects to dictionaries for Unfold
|
35
|
+
return [item.to_dict() for item in dropdown_items]
|
36
|
+
|
37
|
+
|
38
|
+
def get_navigation_config(self) -> List[Dict[str, Any]]:
|
39
|
+
"""Get complete default navigation configuration for Unfold sidebar."""
|
40
|
+
navigation_sections = [
|
41
|
+
NavigationSection(
|
42
|
+
title="Dashboard",
|
43
|
+
separator=True,
|
44
|
+
collapsible=True,
|
45
|
+
items=[
|
46
|
+
NavigationItem(title="Overview", icon=Icons.DASHBOARD, link="/admin/"),
|
47
|
+
NavigationItem(title="Settings", icon=Icons.SETTINGS, link="/admin/constance/config/"),
|
48
|
+
NavigationItem(title="Health Check", icon=Icons.HEALTH_AND_SAFETY, link="/cfg/health/"),
|
49
|
+
]
|
50
|
+
),
|
51
|
+
]
|
52
|
+
|
53
|
+
# Add Accounts section if enabled
|
54
|
+
if self.is_accounts_enabled():
|
55
|
+
navigation_sections.append(NavigationSection(
|
56
|
+
title="Users & Access",
|
57
|
+
separator=True,
|
58
|
+
collapsible=True,
|
59
|
+
items=[
|
60
|
+
NavigationItem(title="Users", icon=Icons.PEOPLE, link="/admin/django_cfg_accounts/customuser/"),
|
61
|
+
NavigationItem(title="User Groups", icon=Icons.GROUP, link="/admin/auth/group/"),
|
62
|
+
NavigationItem(title="Registration Sources", icon=Icons.LINK, link="/admin/django_cfg_accounts/registrationsource/"),
|
63
|
+
NavigationItem(title="User Registration Sources", icon=Icons.PERSON, link="/admin/django_cfg_accounts/userregistrationsource/"),
|
64
|
+
]
|
65
|
+
))
|
66
|
+
|
67
|
+
# Add Support section if enabled
|
68
|
+
if self.is_support_enabled():
|
69
|
+
navigation_sections.append(NavigationSection(
|
70
|
+
title="Support",
|
71
|
+
separator=True,
|
72
|
+
collapsible=True,
|
73
|
+
items=[
|
74
|
+
NavigationItem(title="Tickets", icon=Icons.SUPPORT_AGENT, link="/admin/django_cfg_support/ticket/"),
|
75
|
+
NavigationItem(title="Messages", icon=Icons.CHAT, link="/admin/django_cfg_support/message/"),
|
76
|
+
]
|
77
|
+
))
|
78
|
+
|
79
|
+
# Add Newsletter section if enabled
|
80
|
+
if self.is_newsletter_enabled():
|
81
|
+
navigation_sections.append(NavigationSection(
|
82
|
+
title="Newsletter",
|
83
|
+
separator=True,
|
84
|
+
collapsible=True,
|
85
|
+
items=[
|
86
|
+
NavigationItem(title="Newsletters", icon=Icons.EMAIL, link="/admin/django_cfg_newsletter/newsletter/"),
|
87
|
+
NavigationItem(title="Subscriptions", icon=Icons.PERSON_ADD, link="/admin/django_cfg_newsletter/newslettersubscription/"),
|
88
|
+
NavigationItem(title="Campaigns", icon=Icons.CAMPAIGN, link="/admin/django_cfg_newsletter/newslettercampaign/"),
|
89
|
+
NavigationItem(title="Email Logs", icon=Icons.MAIL_OUTLINE, link="/admin/django_cfg_newsletter/emaillog/"),
|
90
|
+
]
|
91
|
+
))
|
92
|
+
|
93
|
+
# Add Leads section if enabled
|
94
|
+
if self.is_leads_enabled():
|
95
|
+
navigation_sections.append(NavigationSection(
|
96
|
+
title="Leads",
|
97
|
+
separator=True,
|
98
|
+
collapsible=True,
|
99
|
+
items=[
|
100
|
+
NavigationItem(title="Leads", icon=Icons.CONTACT_PAGE, link="/admin/django_cfg_leads/lead/"),
|
101
|
+
]
|
102
|
+
))
|
103
|
+
|
104
|
+
# Add Agents section if enabled
|
105
|
+
if self.is_agents_enabled():
|
106
|
+
navigation_sections.append(NavigationSection(
|
107
|
+
title="AI Agents",
|
108
|
+
separator=True,
|
109
|
+
collapsible=True,
|
110
|
+
items=[
|
111
|
+
NavigationItem(title="Agent Definitions", icon=Icons.SMART_TOY, link="/admin/django_cfg_agents/agentdefinition/"),
|
112
|
+
NavigationItem(title="Agent Templates", icon=Icons.DESCRIPTION, link="/admin/django_cfg_agents/agenttemplate/"),
|
113
|
+
NavigationItem(title="Agent Executions", icon=Icons.PLAY_ARROW, link="/admin/django_cfg_agents/agentexecution/"),
|
114
|
+
NavigationItem(title="Workflow Executions", icon=Icons.AUTORENEW, link="/admin/django_cfg_agents/workflowexecution/"),
|
115
|
+
NavigationItem(title="Tool Executions", icon=Icons.BUILD, link="/admin/django_cfg_agents/toolexecution/"),
|
116
|
+
NavigationItem(title="Toolset Configurations", icon=Icons.SETTINGS, link="/admin/django_cfg_agents/toolsetconfiguration/"),
|
117
|
+
]
|
118
|
+
))
|
119
|
+
|
120
|
+
# Add Knowledge Base section if enabled
|
121
|
+
if self.is_knowbase_enabled():
|
122
|
+
navigation_sections.append(NavigationSection(
|
123
|
+
title="Knowledge Base",
|
124
|
+
separator=True,
|
125
|
+
collapsible=True,
|
126
|
+
items=[
|
127
|
+
NavigationItem(title="Document Categories", icon=Icons.FOLDER, link="/admin/django_cfg_knowbase/documentcategory/"),
|
128
|
+
NavigationItem(title="Documents", icon=Icons.DESCRIPTION, link="/admin/django_cfg_knowbase/document/"),
|
129
|
+
NavigationItem(title="Document Chunks", icon=Icons.TEXT_SNIPPET, link="/admin/django_cfg_knowbase/documentchunk/"),
|
130
|
+
NavigationItem(title="External Data", icon=Icons.CLOUD_SYNC, link="/admin/django_cfg_knowbase/externaldata/"),
|
131
|
+
NavigationItem(title="External Data Chunks", icon=Icons.AUTO_AWESOME_MOTION, link="/admin/django_cfg_knowbase/externaldatachunk/"),
|
132
|
+
NavigationItem(title="Chat Sessions", icon=Icons.CHAT, link="/admin/django_cfg_knowbase/chatsession/"),
|
133
|
+
NavigationItem(title="Chat Messages", icon=Icons.MESSAGE, link="/admin/django_cfg_knowbase/chatmessage/"),
|
134
|
+
]
|
135
|
+
))
|
136
|
+
|
137
|
+
# Add Tasks section if knowbase or agents are enabled
|
138
|
+
if self.is_tasks_enabled():
|
139
|
+
navigation_sections.append(NavigationSection(
|
140
|
+
title="Background Tasks",
|
141
|
+
separator=True,
|
142
|
+
collapsible=True,
|
143
|
+
items=[
|
144
|
+
NavigationItem(title="Task Queue", icon=Icons.QUEUE, link="/admin/django_dramatiq/task/"),
|
145
|
+
NavigationItem(title="Task Dashboard", icon=Icons.SETTINGS_APPLICATIONS, link="/cfg/tasks/dashboard/"),
|
146
|
+
]
|
147
|
+
))
|
148
|
+
|
149
|
+
# Convert all NavigationSection objects to dictionaries
|
150
|
+
return [section.to_dict() for section in navigation_sections]
|
151
|
+
|
152
|
+
|
153
|
+
def get_unfold_config(self) -> Dict[str, Any]:
|
154
|
+
"""Get complete Unfold configuration based on working old version."""
|
155
|
+
return {
|
156
|
+
# Site branding and appearance
|
157
|
+
"SITE_TITLE": "Admin",
|
158
|
+
"SITE_HEADER": "Admin",
|
159
|
+
"SITE_SUBHEADER": "",
|
160
|
+
"SITE_URL": "/",
|
161
|
+
"SITE_SYMBOL": "dashboard",
|
162
|
+
|
163
|
+
# UI visibility controls
|
164
|
+
"SHOW_HISTORY": True,
|
165
|
+
"SHOW_VIEW_ON_SITE": True,
|
166
|
+
"SHOW_BACK_BUTTON": False,
|
167
|
+
|
168
|
+
# Dashboard callback
|
169
|
+
"DASHBOARD_CALLBACK": "api.dashboard.callbacks.main_dashboard_callback",
|
170
|
+
|
171
|
+
# Theme configuration
|
172
|
+
"THEME": None, # Auto-detect or force "dark"/"light"
|
173
|
+
|
174
|
+
# Login page customization
|
175
|
+
"LOGIN": {
|
176
|
+
"redirect_after": lambda request: "/admin/",
|
177
|
+
},
|
178
|
+
|
179
|
+
# Design system
|
180
|
+
"BORDER_RADIUS": "8px",
|
181
|
+
"COLORS": {
|
182
|
+
"base": {
|
183
|
+
"50": "249, 250, 251",
|
184
|
+
"100": "243, 244, 246",
|
185
|
+
"200": "229, 231, 235",
|
186
|
+
"300": "209, 213, 219",
|
187
|
+
"400": "156, 163, 175",
|
188
|
+
"500": "107, 114, 128",
|
189
|
+
"600": "75, 85, 99",
|
190
|
+
"700": "55, 65, 81",
|
191
|
+
"800": "31, 41, 55",
|
192
|
+
"900": "17, 24, 39",
|
193
|
+
"950": "3, 7, 18",
|
194
|
+
},
|
195
|
+
"primary": {
|
196
|
+
"50": "239, 246, 255",
|
197
|
+
"100": "219, 234, 254",
|
198
|
+
"200": "191, 219, 254",
|
199
|
+
"300": "147, 197, 253",
|
200
|
+
"400": "96, 165, 250",
|
201
|
+
"500": "59, 130, 246",
|
202
|
+
"600": "37, 99, 235",
|
203
|
+
"700": "29, 78, 216",
|
204
|
+
"800": "30, 64, 175",
|
205
|
+
"900": "30, 58, 138",
|
206
|
+
"950": "23, 37, 84",
|
207
|
+
},
|
208
|
+
"font": {
|
209
|
+
"subtle-light": "var(--color-base-500)",
|
210
|
+
"subtle-dark": "var(--color-base-400)",
|
211
|
+
"default-light": "var(--color-base-600)",
|
212
|
+
"default-dark": "var(--color-base-300)",
|
213
|
+
"important-light": "var(--color-base-900)",
|
214
|
+
"important-dark": "var(--color-base-100)",
|
215
|
+
},
|
216
|
+
},
|
217
|
+
|
218
|
+
# Sidebar navigation - KEY STRUCTURE!
|
219
|
+
"SIDEBAR": {
|
220
|
+
"show_search": True,
|
221
|
+
"command_search": True,
|
222
|
+
"show_all_applications": True,
|
223
|
+
"navigation": self.get_navigation_config(),
|
224
|
+
},
|
225
|
+
|
226
|
+
# Site dropdown menu - handled by config.py to allow extending
|
227
|
+
# "SITE_DROPDOWN": self._get_default_dropdown_items(),
|
228
|
+
|
229
|
+
# Command interface
|
230
|
+
"COMMAND": {
|
231
|
+
"search_models": True,
|
232
|
+
"show_history": True,
|
233
|
+
},
|
234
|
+
|
235
|
+
# Multi-language support - DISABLED
|
236
|
+
"SHOW_LANGUAGES": False,
|
237
|
+
}
|
238
|
+
|
239
|
+
def get_widgets_config(self) -> List[Dict[str, Any]]:
|
240
|
+
"""Get dashboard widgets configuration using Pydantic models."""
|
241
|
+
# Create system overview widget with StatCard models
|
242
|
+
system_overview_widget = StatsCardsWidget(
|
243
|
+
title="System Overview",
|
244
|
+
cards=[
|
245
|
+
StatCard(
|
246
|
+
title="CPU Usage",
|
247
|
+
value="{{ cpu_percent }}%",
|
248
|
+
icon=Icons.MEMORY,
|
249
|
+
color="blue",
|
250
|
+
),
|
251
|
+
StatCard(
|
252
|
+
title="Memory Usage",
|
253
|
+
value="{{ memory_percent }}%",
|
254
|
+
icon=Icons.STORAGE,
|
255
|
+
color="green",
|
256
|
+
),
|
257
|
+
StatCard(
|
258
|
+
title="Disk Usage",
|
259
|
+
value="{{ disk_percent }}%",
|
260
|
+
icon=Icons.FOLDER,
|
261
|
+
color="orange",
|
262
|
+
),
|
263
|
+
]
|
264
|
+
)
|
265
|
+
|
266
|
+
# Convert to dictionaries for Unfold
|
267
|
+
return [system_overview_widget.to_dict()]
|
268
|
+
|
269
|
+
|
270
|
+
# Lazy initialization to avoid circular imports
|
271
|
+
_dashboard_manager = None
|
272
|
+
|
273
|
+
def get_dashboard_manager() -> DashboardManager:
|
274
|
+
"""Get the global dashboard manager instance."""
|
275
|
+
global _dashboard_manager
|
276
|
+
if _dashboard_manager is None:
|
277
|
+
_dashboard_manager = DashboardManager()
|
278
|
+
return _dashboard_manager
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# Material Icons for Django CFG Unfold
|
2
|
+
|
3
|
+
This module provides Material Design Icons integration for Django CFG Unfold admin interface.
|
4
|
+
|
5
|
+
## 📊 Statistics
|
6
|
+
|
7
|
+
- **Total Icons**: 2234
|
8
|
+
- **Categories**: 24
|
9
|
+
- **Auto-generated**: Yes (via `generate_icons.py`)
|
10
|
+
|
11
|
+
## 🚀 Usage
|
12
|
+
|
13
|
+
### Basic Usage
|
14
|
+
|
15
|
+
```python
|
16
|
+
from django_cfg.modules.django_unfold.icons import Icons
|
17
|
+
|
18
|
+
# Use in navigation configuration
|
19
|
+
navigation_item = {
|
20
|
+
"title": "Dashboard",
|
21
|
+
"icon": Icons.DASHBOARD, # IDE autocompletion!
|
22
|
+
"link": "/admin/",
|
23
|
+
}
|
24
|
+
```
|
25
|
+
|
26
|
+
### Category-based Selection
|
27
|
+
|
28
|
+
```python
|
29
|
+
from django_cfg.modules.django_unfold.icons import IconCategories
|
30
|
+
|
31
|
+
# Get all navigation-related icons
|
32
|
+
nav_icons = IconCategories.NAVIGATION
|
33
|
+
|
34
|
+
# Get all user-related icons
|
35
|
+
user_icons = IconCategories.USERS
|
36
|
+
```
|
37
|
+
|
38
|
+
### Validation
|
39
|
+
|
40
|
+
```python
|
41
|
+
from django_cfg.modules.django_unfold.icons import validate_icon_constant
|
42
|
+
|
43
|
+
# Validate icon exists
|
44
|
+
is_valid = validate_icon_constant(Icons.DASHBOARD) # True
|
45
|
+
is_valid = validate_icon_constant("nonexistent") # False
|
46
|
+
```
|
47
|
+
|
48
|
+
## 🔄 Updating Icons
|
49
|
+
|
50
|
+
To update to the latest Material Icons:
|
51
|
+
|
52
|
+
```bash
|
53
|
+
cd /path/to/django-cfg/src/django_cfg/modules/django_unfold/icons/
|
54
|
+
python generate_icons.py
|
55
|
+
```
|
56
|
+
|
57
|
+
This will:
|
58
|
+
1. Download the latest Material Icons from Google
|
59
|
+
2. Generate new `constants.py` with all icons
|
60
|
+
3. Categorize icons for easy discovery
|
61
|
+
4. Provide IDE-friendly autocompletion
|
62
|
+
|
63
|
+
## 📂 File Structure
|
64
|
+
|
65
|
+
```
|
66
|
+
icons/
|
67
|
+
├── __init__.py # Main exports
|
68
|
+
├── constants.py # 🤖 Auto-generated icon constants
|
69
|
+
├── icons.py # MaterialIcons class & validation
|
70
|
+
├── icon_validator.py # Navigation validation utilities
|
71
|
+
├── generate_icons.py # 🔄 Icon generator script
|
72
|
+
├── example_usage.py # Usage examples
|
73
|
+
└── README.md # This file
|
74
|
+
```
|
75
|
+
|
76
|
+
## 🎯 Available Categories
|
77
|
+
|
78
|
+
- **Navigation** (124 icons): add_home, add_home_work, add_home_work, add_to_home_screen, app_settings_alt, ... (+119 more)
|
79
|
+
- **Users** (54 icons): account_balance, account_balance_wallet, account_box, account_circle, account_tree, ... (+49 more)
|
80
|
+
- **Documents** (70 icons): article, attach_file, audio_file, contact_page, create_new_folder, ... (+65 more)
|
81
|
+
- **Communication** (174 icons): 3p, add_call, add_comment, add_ic_call, add_ic_call, ... (+169 more)
|
82
|
+
- **Ai_Automation** (39 icons): auto_awesome, auto_awesome_mosaic, auto_awesome_motion, auto_delete, auto_fix_high, ... (+34 more)
|
83
|
+
- **Actions** (124 icons): add, add_a_photo, add_alarm, add_alert, add_box, ... (+119 more)
|
84
|
+
- **Status** (36 icons): check, check_box, check_box_outline_blank, check_circle, check_circle_outline, ... (+31 more)
|
85
|
+
- **Media** (82 icons): assistant_photo, audiotrack, bluetooth_audio, broken_image, camera, ... (+77 more)
|
86
|
+
- **Settings** (26 icons): admin_panel_settings, app_settings_alt, build, build_circle, construction, ... (+21 more)
|
87
|
+
- **Commerce** (18 icons): attach_money, local_convenience_store, local_grocery_store, money, money_off, ... (+13 more)
|
88
|
+
- **Travel** (61 icons): car_crash, car_rental, car_repair, card_giftcard, card_membership, ... (+56 more)
|
89
|
+
- **Social** (214 icons): 18_up_rating, 6_ft_apart, add_moderator, add_reaction, architecture, ... (+209 more)
|
90
|
+
- **Device** (217 icons): 1x_mobiledata, 30fps, 3g_mobiledata, 4g_mobiledata, 4g_plus_mobiledata, ... (+212 more)
|
91
|
+
- **Editor** (162 icons): add_chart, add_comment, align_horizontal_center, align_horizontal_center, align_horizontal_left, ... (+157 more)
|
92
|
+
- **Maps** (228 icons): 360, add_business, add_location, add_location_alt, add_road, ... (+223 more)
|
93
|
+
- **Notification** (83 icons): account_tree, adb, airline_seat_flat, airline_seat_flat_angled, airline_seat_individual_suite, ... (+78 more)
|
94
|
+
- **Content** (105 icons): 30fps_select, 60fps_select, add, add_box, add_circle, ... (+100 more)
|
95
|
+
- **Hardware** (128 icons): adf_scanner, battery_0_bar, battery_1_bar, battery_2_bar, battery_3_bar, ... (+123 more)
|
96
|
+
- **Image** (286 icons): 10mp, 11mp, 12mp, 13mp, 14mp, ... (+281 more)
|
97
|
+
- **Av** (125 icons): 10k, 1k, 1k_plus, 2k, 2k_plus, ... (+120 more)
|
98
|
+
- **Places** (99 icons): ac_unit, airport_shuttle, all_inclusive, apartment, assured_workload, ... (+94 more)
|
99
|
+
- **File** (54 icons): approval, archive, attach_email, attachment, attachment, ... (+49 more)
|
100
|
+
- **Toggle** (193 icons): 3d_rotation, airplanemode_off, airplanemode_on, alarm_off, alarm_on, ... (+188 more)
|
101
|
+
- **Other** (1138 icons): 10k, 10mp, 11mp, 123, 12mp, ... (+1133 more)
|
102
|
+
|
103
|
+
## 🛠️ Development
|
104
|
+
|
105
|
+
### Adding New Categories
|
106
|
+
|
107
|
+
Edit the `category_keywords` in `generate_icons.py`:
|
108
|
+
|
109
|
+
```python
|
110
|
+
category_keywords = {
|
111
|
+
'my_category': ['keyword1', 'keyword2', 'keyword3'],
|
112
|
+
# ...
|
113
|
+
}
|
114
|
+
```
|
115
|
+
|
116
|
+
### Custom Icon Validation
|
117
|
+
|
118
|
+
```python
|
119
|
+
from django_cfg.modules.django_unfold.icons import MaterialIcons
|
120
|
+
|
121
|
+
# Check if icon exists
|
122
|
+
if MaterialIcons.is_valid_icon('my_icon'):
|
123
|
+
print("Icon exists!")
|
124
|
+
|
125
|
+
# Get suggestions for invalid icons
|
126
|
+
suggestions = MaterialIcons.suggest_similar_icons('invalid_icon')
|
127
|
+
print(f"Did you mean: {suggestions}")
|
128
|
+
```
|
129
|
+
|
130
|
+
## 📋 Icon Guidelines
|
131
|
+
|
132
|
+
1. **Use Constants**: Always use `Icons.CONSTANT_NAME` instead of strings
|
133
|
+
2. **Validate**: Use validation functions to check icon existence
|
134
|
+
3. **Categories**: Browse `IconCategories` for organized icon selection
|
135
|
+
4. **Update Regularly**: Run the generator script to get latest icons
|
136
|
+
|
137
|
+
## 🔗 Resources
|
138
|
+
|
139
|
+
- [Material Design Icons](https://fonts.google.com/icons)
|
140
|
+
- [Google Material Icons GitHub](https://github.com/google/material-design-icons)
|
141
|
+
- [Django Unfold Documentation](https://unfoldadmin.com/)
|
142
|
+
|
143
|
+
---
|
144
|
+
|
145
|
+
*This file is auto-generated. Last updated: 2025-09-21 01:14:22*
|