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,486 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Material Icons Generator for Django CFG Unfold.
|
4
|
+
|
5
|
+
This script automatically downloads the latest Material Icons from Google
|
6
|
+
and generates IDE-friendly constants for better autocompletion.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import os
|
10
|
+
import sys
|
11
|
+
import json
|
12
|
+
import requests
|
13
|
+
from pathlib import Path
|
14
|
+
from typing import Dict, List, Set
|
15
|
+
import logging
|
16
|
+
|
17
|
+
# Setup logging
|
18
|
+
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
|
19
|
+
logger = logging.getLogger(__name__)
|
20
|
+
|
21
|
+
|
22
|
+
class MaterialIconsGenerator:
|
23
|
+
"""Generator for Material Icons constants."""
|
24
|
+
|
25
|
+
# URLs for different sources
|
26
|
+
SOURCES = {
|
27
|
+
'codepoints': 'https://raw.githubusercontent.com/google/material-design-icons/master/font/MaterialIcons-Regular.codepoints',
|
28
|
+
'metadata': 'https://fonts.google.com/metadata/icons',
|
29
|
+
'github_api': 'https://api.github.com/repos/google/material-design-icons/contents/symbols'
|
30
|
+
}
|
31
|
+
|
32
|
+
def __init__(self, output_dir: Path):
|
33
|
+
self.output_dir = Path(output_dir)
|
34
|
+
self.icons_data: Dict[str, str] = {}
|
35
|
+
self.categories: Dict[str, List[str]] = {}
|
36
|
+
|
37
|
+
def download_codepoints(self) -> Dict[str, str]:
|
38
|
+
"""Download Material Icons codepoints from GitHub."""
|
39
|
+
logger.info("š„ Downloading Material Icons codepoints...")
|
40
|
+
|
41
|
+
try:
|
42
|
+
response = requests.get(self.SOURCES['codepoints'], timeout=30)
|
43
|
+
response.raise_for_status()
|
44
|
+
|
45
|
+
icons = {}
|
46
|
+
for line in response.text.strip().split('\n'):
|
47
|
+
if line.strip() and not line.startswith('#'):
|
48
|
+
parts = line.split()
|
49
|
+
if len(parts) >= 2:
|
50
|
+
name = parts[0]
|
51
|
+
codepoint = parts[1]
|
52
|
+
icons[name] = codepoint
|
53
|
+
|
54
|
+
logger.info(f"ā
Downloaded {len(icons)} icons from codepoints")
|
55
|
+
return icons
|
56
|
+
|
57
|
+
except Exception as e:
|
58
|
+
logger.error(f"ā Failed to download codepoints: {e}")
|
59
|
+
return {}
|
60
|
+
|
61
|
+
def download_metadata(self) -> Dict[str, any]:
|
62
|
+
"""Download Material Icons metadata from Google Fonts."""
|
63
|
+
logger.info("š„ Downloading Material Icons metadata...")
|
64
|
+
|
65
|
+
try:
|
66
|
+
response = requests.get(self.SOURCES['metadata'], timeout=30)
|
67
|
+
response.raise_for_status()
|
68
|
+
|
69
|
+
# Remove the first line (it's not JSON)
|
70
|
+
content = response.text
|
71
|
+
if content.startswith(")]}'"):
|
72
|
+
content = content[4:]
|
73
|
+
|
74
|
+
metadata = json.loads(content)
|
75
|
+
|
76
|
+
# Extract icons from metadata
|
77
|
+
icons_metadata = {}
|
78
|
+
if 'icons' in metadata:
|
79
|
+
for icon in metadata['icons']:
|
80
|
+
name = icon.get('name', '')
|
81
|
+
if name:
|
82
|
+
icons_metadata[name] = {
|
83
|
+
'categories': icon.get('categories', []),
|
84
|
+
'tags': icon.get('tags', []),
|
85
|
+
'version': icon.get('version', 1),
|
86
|
+
'popularity': icon.get('popularity', 0)
|
87
|
+
}
|
88
|
+
|
89
|
+
logger.info(f"ā
Downloaded metadata for {len(icons_metadata)} icons")
|
90
|
+
return icons_metadata
|
91
|
+
|
92
|
+
except Exception as e:
|
93
|
+
logger.warning(f"ā ļø Failed to download metadata: {e}")
|
94
|
+
return {}
|
95
|
+
|
96
|
+
def categorize_icons(self, metadata: Dict[str, any]) -> Dict[str, List[str]]:
|
97
|
+
"""Categorize icons based on metadata."""
|
98
|
+
categories = {
|
99
|
+
'navigation': [],
|
100
|
+
'users': [],
|
101
|
+
'documents': [],
|
102
|
+
'communication': [],
|
103
|
+
'ai_automation': [],
|
104
|
+
'actions': [],
|
105
|
+
'status': [],
|
106
|
+
'media': [],
|
107
|
+
'settings': [],
|
108
|
+
'commerce': [],
|
109
|
+
'travel': [],
|
110
|
+
'social': [],
|
111
|
+
'device': [],
|
112
|
+
'editor': [],
|
113
|
+
'maps': [],
|
114
|
+
'notification': [],
|
115
|
+
'content': [],
|
116
|
+
'hardware': [],
|
117
|
+
'image': [],
|
118
|
+
'av': [],
|
119
|
+
'places': [],
|
120
|
+
'file': [],
|
121
|
+
'toggle': [],
|
122
|
+
}
|
123
|
+
|
124
|
+
# Keywords for categorization
|
125
|
+
category_keywords = {
|
126
|
+
'navigation': ['dashboard', 'menu', 'home', 'apps', 'navigate', 'arrow', 'chevron', 'expand', 'more'],
|
127
|
+
'users': ['people', 'person', 'group', 'account', 'face', 'user', 'profile'],
|
128
|
+
'documents': ['description', 'text', 'article', 'note', 'folder', 'file', 'document', 'page'],
|
129
|
+
'communication': ['chat', 'message', 'email', 'mail', 'forum', 'comment', 'call', 'phone'],
|
130
|
+
'ai_automation': ['smart', 'auto', 'sync', 'refresh', 'repeat', 'psychology', 'memory', 'robot'],
|
131
|
+
'actions': ['play', 'pause', 'stop', 'add', 'remove', 'edit', 'delete', 'save', 'cancel', 'done'],
|
132
|
+
'status': ['check', 'error', 'warning', 'info', 'pending', 'success', 'failed'],
|
133
|
+
'media': ['video', 'audio', 'music', 'photo', 'image', 'camera', 'mic', 'volume'],
|
134
|
+
'settings': ['settings', 'tune', 'build', 'construction', 'gear', 'config'],
|
135
|
+
'commerce': ['shopping', 'cart', 'store', 'payment', 'money', 'price', 'sell'],
|
136
|
+
'travel': ['flight', 'hotel', 'car', 'train', 'directions', 'map', 'location'],
|
137
|
+
'social': ['share', 'favorite', 'like', 'star', 'bookmark', 'follow'],
|
138
|
+
'device': ['phone', 'tablet', 'laptop', 'desktop', 'watch', 'tv', 'speaker'],
|
139
|
+
'editor': ['format', 'text', 'font', 'color', 'align', 'indent', 'bold', 'italic'],
|
140
|
+
'maps': ['map', 'location', 'place', 'pin', 'navigation', 'gps'],
|
141
|
+
'notification': ['notification', 'alert', 'bell', 'announce'],
|
142
|
+
'content': ['content', 'copy', 'paste', 'cut', 'select', 'clipboard'],
|
143
|
+
'hardware': ['memory', 'storage', 'battery', 'wifi', 'bluetooth', 'usb'],
|
144
|
+
'image': ['image', 'photo', 'picture', 'crop', 'filter', 'camera'],
|
145
|
+
'av': ['play', 'pause', 'stop', 'volume', 'music', 'video', 'audio'],
|
146
|
+
'places': ['home', 'work', 'school', 'hospital', 'restaurant', 'hotel'],
|
147
|
+
'file': ['folder', 'file', 'upload', 'download', 'attach', 'archive'],
|
148
|
+
'toggle': ['toggle', 'switch', 'radio', 'checkbox', 'on', 'off'],
|
149
|
+
}
|
150
|
+
|
151
|
+
for icon_name in self.icons_data.keys():
|
152
|
+
# Use metadata categories if available
|
153
|
+
if icon_name in metadata and metadata[icon_name].get('categories'):
|
154
|
+
for cat in metadata[icon_name]['categories']:
|
155
|
+
cat_key = cat.lower().replace(' ', '_')
|
156
|
+
if cat_key in categories:
|
157
|
+
categories[cat_key].append(icon_name)
|
158
|
+
continue
|
159
|
+
|
160
|
+
# Fallback to keyword matching
|
161
|
+
categorized = False
|
162
|
+
for category, keywords in category_keywords.items():
|
163
|
+
if any(keyword in icon_name.lower() for keyword in keywords):
|
164
|
+
categories[category].append(icon_name)
|
165
|
+
categorized = True
|
166
|
+
break
|
167
|
+
|
168
|
+
# Default category for uncategorized icons
|
169
|
+
if not categorized:
|
170
|
+
categories.setdefault('other', []).append(icon_name)
|
171
|
+
|
172
|
+
# Remove empty categories and sort icons
|
173
|
+
return {k: sorted(v) for k, v in categories.items() if v}
|
174
|
+
|
175
|
+
def generate_constants_file(self):
|
176
|
+
"""Generate the constants.py file with all icons."""
|
177
|
+
logger.info("š Generating constants.py...")
|
178
|
+
|
179
|
+
# Sort icons alphabetically
|
180
|
+
sorted_icons = sorted(self.icons_data.keys())
|
181
|
+
|
182
|
+
content = '''"""
|
183
|
+
Material Icons constants for IDE autocompletion.
|
184
|
+
|
185
|
+
This file is auto-generated by generate_icons.py script.
|
186
|
+
DO NOT EDIT MANUALLY - run the script to update.
|
187
|
+
|
188
|
+
Generated from Google Material Design Icons.
|
189
|
+
Total icons: {total_icons}
|
190
|
+
"""
|
191
|
+
|
192
|
+
from typing import Dict, Final
|
193
|
+
|
194
|
+
|
195
|
+
class Icons:
|
196
|
+
"""
|
197
|
+
Material Design Icons constants for IDE autocompletion.
|
198
|
+
|
199
|
+
Usage:
|
200
|
+
from django_cfg.modules.django_unfold.icons import Icons
|
201
|
+
|
202
|
+
# IDE will provide autocompletion
|
203
|
+
icon = Icons.DASHBOARD
|
204
|
+
icon = Icons.SETTINGS
|
205
|
+
icon = Icons.PEOPLE
|
206
|
+
"""
|
207
|
+
|
208
|
+
'''.format(total_icons=len(sorted_icons))
|
209
|
+
|
210
|
+
# Generate icon constants
|
211
|
+
for icon_name in sorted_icons:
|
212
|
+
# Convert to valid Python identifier
|
213
|
+
const_name = icon_name.upper().replace('-', '_')
|
214
|
+
# Prefix with underscore if starts with digit
|
215
|
+
if const_name[0].isdigit():
|
216
|
+
const_name = f'_{const_name}'
|
217
|
+
content += f' {const_name}: Final[str] = "{icon_name}"\n'
|
218
|
+
|
219
|
+
# Add common aliases
|
220
|
+
content += '''
|
221
|
+
# Common aliases for better IDE experience
|
222
|
+
USERS = PEOPLE
|
223
|
+
USER = PERSON
|
224
|
+
DOCUMENTS = DESCRIPTION
|
225
|
+
FILES = INSERT_DRIVE_FILE
|
226
|
+
FOLDERS = FOLDER
|
227
|
+
MESSAGES = MESSAGE
|
228
|
+
EMAILS = EMAIL
|
229
|
+
TASKS = QUEUE
|
230
|
+
AGENTS = SMART_TOY
|
231
|
+
AI = SMART_TOY
|
232
|
+
|
233
|
+
|
234
|
+
'''
|
235
|
+
|
236
|
+
# Generate categories
|
237
|
+
content += '''# IDE-friendly icon categories for easy discovery
|
238
|
+
class IconCategories:
|
239
|
+
"""Categorized icon collections for easy discovery."""
|
240
|
+
|
241
|
+
'''
|
242
|
+
|
243
|
+
for category, icons in self.categories.items():
|
244
|
+
if len(icons) > 0:
|
245
|
+
category_name = category.upper()
|
246
|
+
content += f' {category_name}: Dict[str, str] = {{\n'
|
247
|
+
for icon in icons[:20]: # Limit to first 20 icons per category
|
248
|
+
const_name = icon.upper().replace('-', '_')
|
249
|
+
# Prefix with underscore if starts with digit
|
250
|
+
if const_name[0].isdigit():
|
251
|
+
const_name = f'_{const_name}'
|
252
|
+
content += f" '{icon}': Icons.{const_name},\n"
|
253
|
+
content += ' }\n \n'
|
254
|
+
|
255
|
+
# Add validation function
|
256
|
+
content += '''
|
257
|
+
|
258
|
+
# Validation function for IDE
|
259
|
+
def validate_icon_constant(icon_name: str) -> bool:
|
260
|
+
"""
|
261
|
+
Validate that an icon constant exists.
|
262
|
+
|
263
|
+
Args:
|
264
|
+
icon_name: The icon name to validate
|
265
|
+
|
266
|
+
Returns:
|
267
|
+
True if the icon exists in Material Icons
|
268
|
+
"""
|
269
|
+
from .icons import MaterialIcons
|
270
|
+
return MaterialIcons.is_valid_icon(icon_name)
|
271
|
+
|
272
|
+
|
273
|
+
# Export commonly used icons for direct import
|
274
|
+
__all__ = [
|
275
|
+
'Icons',
|
276
|
+
'IconCategories',
|
277
|
+
'validate_icon_constant',
|
278
|
+
]
|
279
|
+
'''
|
280
|
+
|
281
|
+
# Write to file
|
282
|
+
output_file = self.output_dir / 'constants.py'
|
283
|
+
with open(output_file, 'w', encoding='utf-8') as f:
|
284
|
+
f.write(content)
|
285
|
+
|
286
|
+
logger.info(f"ā
Generated {output_file} with {len(sorted_icons)} icons")
|
287
|
+
|
288
|
+
def generate_readme(self):
|
289
|
+
"""Generate README.md for the icons module."""
|
290
|
+
logger.info("š Generating README.md...")
|
291
|
+
|
292
|
+
content = f'''# Material Icons for Django CFG Unfold
|
293
|
+
|
294
|
+
This module provides Material Design Icons integration for Django CFG Unfold admin interface.
|
295
|
+
|
296
|
+
## š Statistics
|
297
|
+
|
298
|
+
- **Total Icons**: {len(self.icons_data)}
|
299
|
+
- **Categories**: {len(self.categories)}
|
300
|
+
- **Auto-generated**: Yes (via `generate_icons.py`)
|
301
|
+
|
302
|
+
## š Usage
|
303
|
+
|
304
|
+
### Basic Usage
|
305
|
+
|
306
|
+
```python
|
307
|
+
from django_cfg.modules.django_unfold.icons import Icons
|
308
|
+
|
309
|
+
# Use in navigation configuration
|
310
|
+
navigation_item = {{
|
311
|
+
"title": "Dashboard",
|
312
|
+
"icon": Icons.DASHBOARD, # IDE autocompletion!
|
313
|
+
"link": "/admin/",
|
314
|
+
}}
|
315
|
+
```
|
316
|
+
|
317
|
+
### Category-based Selection
|
318
|
+
|
319
|
+
```python
|
320
|
+
from django_cfg.modules.django_unfold.icons import IconCategories
|
321
|
+
|
322
|
+
# Get all navigation-related icons
|
323
|
+
nav_icons = IconCategories.NAVIGATION
|
324
|
+
|
325
|
+
# Get all user-related icons
|
326
|
+
user_icons = IconCategories.USERS
|
327
|
+
```
|
328
|
+
|
329
|
+
### Validation
|
330
|
+
|
331
|
+
```python
|
332
|
+
from django_cfg.modules.django_unfold.icons import validate_icon_constant
|
333
|
+
|
334
|
+
# Validate icon exists
|
335
|
+
is_valid = validate_icon_constant(Icons.DASHBOARD) # True
|
336
|
+
is_valid = validate_icon_constant("nonexistent") # False
|
337
|
+
```
|
338
|
+
|
339
|
+
## š Updating Icons
|
340
|
+
|
341
|
+
To update to the latest Material Icons:
|
342
|
+
|
343
|
+
```bash
|
344
|
+
cd /path/to/django-cfg/src/django_cfg/modules/django_unfold/icons/
|
345
|
+
python generate_icons.py
|
346
|
+
```
|
347
|
+
|
348
|
+
This will:
|
349
|
+
1. Download the latest Material Icons from Google
|
350
|
+
2. Generate new `constants.py` with all icons
|
351
|
+
3. Categorize icons for easy discovery
|
352
|
+
4. Provide IDE-friendly autocompletion
|
353
|
+
|
354
|
+
## š File Structure
|
355
|
+
|
356
|
+
```
|
357
|
+
icons/
|
358
|
+
āāā __init__.py # Main exports
|
359
|
+
āāā constants.py # š¤ Auto-generated icon constants
|
360
|
+
āāā icons.py # MaterialIcons class & validation
|
361
|
+
āāā icon_validator.py # Navigation validation utilities
|
362
|
+
āāā generate_icons.py # š Icon generator script
|
363
|
+
āāā example_usage.py # Usage examples
|
364
|
+
āāā README.md # This file
|
365
|
+
```
|
366
|
+
|
367
|
+
## šÆ Available Categories
|
368
|
+
|
369
|
+
{self._generate_categories_list()}
|
370
|
+
|
371
|
+
## š ļø Development
|
372
|
+
|
373
|
+
### Adding New Categories
|
374
|
+
|
375
|
+
Edit the `category_keywords` in `generate_icons.py`:
|
376
|
+
|
377
|
+
```python
|
378
|
+
category_keywords = {{
|
379
|
+
'my_category': ['keyword1', 'keyword2', 'keyword3'],
|
380
|
+
# ...
|
381
|
+
}}
|
382
|
+
```
|
383
|
+
|
384
|
+
### Custom Icon Validation
|
385
|
+
|
386
|
+
```python
|
387
|
+
from django_cfg.modules.django_unfold.icons import MaterialIcons
|
388
|
+
|
389
|
+
# Check if icon exists
|
390
|
+
if MaterialIcons.is_valid_icon('my_icon'):
|
391
|
+
print("Icon exists!")
|
392
|
+
|
393
|
+
# Get suggestions for invalid icons
|
394
|
+
suggestions = MaterialIcons.suggest_similar_icons('invalid_icon')
|
395
|
+
print(f"Did you mean: {{suggestions}}")
|
396
|
+
```
|
397
|
+
|
398
|
+
## š Icon Guidelines
|
399
|
+
|
400
|
+
1. **Use Constants**: Always use `Icons.CONSTANT_NAME` instead of strings
|
401
|
+
2. **Validate**: Use validation functions to check icon existence
|
402
|
+
3. **Categories**: Browse `IconCategories` for organized icon selection
|
403
|
+
4. **Update Regularly**: Run the generator script to get latest icons
|
404
|
+
|
405
|
+
## š Resources
|
406
|
+
|
407
|
+
- [Material Design Icons](https://fonts.google.com/icons)
|
408
|
+
- [Google Material Icons GitHub](https://github.com/google/material-design-icons)
|
409
|
+
- [Django Unfold Documentation](https://unfoldadmin.com/)
|
410
|
+
|
411
|
+
---
|
412
|
+
|
413
|
+
*This file is auto-generated. Last updated: {self._get_current_timestamp()}*
|
414
|
+
'''
|
415
|
+
|
416
|
+
# Write to file
|
417
|
+
output_file = self.output_dir / 'README.md'
|
418
|
+
with open(output_file, 'w', encoding='utf-8') as f:
|
419
|
+
f.write(content)
|
420
|
+
|
421
|
+
logger.info(f"ā
Generated {output_file}")
|
422
|
+
|
423
|
+
def _generate_categories_list(self) -> str:
|
424
|
+
"""Generate markdown list of categories."""
|
425
|
+
lines = []
|
426
|
+
for category, icons in self.categories.items():
|
427
|
+
icon_count = len(icons)
|
428
|
+
example_icons = ', '.join(icons[:5])
|
429
|
+
if len(icons) > 5:
|
430
|
+
example_icons += f", ... (+{len(icons) - 5} more)"
|
431
|
+
|
432
|
+
lines.append(f"- **{category.title()}** ({icon_count} icons): {example_icons}")
|
433
|
+
|
434
|
+
return '\n'.join(lines)
|
435
|
+
|
436
|
+
def _get_current_timestamp(self) -> str:
|
437
|
+
"""Get current timestamp for documentation."""
|
438
|
+
from datetime import datetime
|
439
|
+
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
440
|
+
|
441
|
+
def run(self):
|
442
|
+
"""Run the complete icon generation process."""
|
443
|
+
logger.info("š Starting Material Icons generation...")
|
444
|
+
|
445
|
+
# Download icons data
|
446
|
+
self.icons_data = self.download_codepoints()
|
447
|
+
if not self.icons_data:
|
448
|
+
logger.error("ā Failed to download icons data")
|
449
|
+
return False
|
450
|
+
|
451
|
+
# Download metadata for categorization
|
452
|
+
metadata = self.download_metadata()
|
453
|
+
|
454
|
+
# Categorize icons
|
455
|
+
self.categories = self.categorize_icons(metadata)
|
456
|
+
logger.info(f"š Categorized icons into {len(self.categories)} categories")
|
457
|
+
|
458
|
+
# Generate files
|
459
|
+
self.generate_constants_file()
|
460
|
+
self.generate_readme()
|
461
|
+
|
462
|
+
logger.info("š Icon generation completed successfully!")
|
463
|
+
return True
|
464
|
+
|
465
|
+
|
466
|
+
def main():
|
467
|
+
"""Main entry point."""
|
468
|
+
# Get the directory where this script is located
|
469
|
+
script_dir = Path(__file__).parent
|
470
|
+
|
471
|
+
generator = MaterialIconsGenerator(script_dir)
|
472
|
+
success = generator.run()
|
473
|
+
|
474
|
+
if success:
|
475
|
+
print("\nā
Material Icons updated successfully!")
|
476
|
+
print("š Files generated:")
|
477
|
+
print(f" - {script_dir / 'constants.py'}")
|
478
|
+
print(f" - {script_dir / 'README.md'}")
|
479
|
+
print("\nš” Don't forget to commit the changes!")
|
480
|
+
else:
|
481
|
+
print("\nā Icon generation failed!")
|
482
|
+
sys.exit(1)
|
483
|
+
|
484
|
+
|
485
|
+
if __name__ == '__main__':
|
486
|
+
main()
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""
|
2
|
+
Unfold Models Package
|
3
|
+
|
4
|
+
All Pydantic models for Django Unfold admin interface.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .config import UnfoldConfig, UnfoldTheme, UnfoldColors, UnfoldSidebar, UnfoldThemeConfig, UnfoldDashboardConfig
|
8
|
+
from .navigation import NavigationItem, NavigationSection, NavigationItemType
|
9
|
+
from .dropdown import SiteDropdownItem
|
10
|
+
from .dashboard import StatCard, SystemHealthItem, QuickAction, DashboardWidget, DashboardData, ChartDataset, ChartData
|
11
|
+
from .tabs import TabConfiguration, TabItem
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
# Config models
|
15
|
+
'UnfoldConfig',
|
16
|
+
'UnfoldTheme',
|
17
|
+
'UnfoldColors',
|
18
|
+
'UnfoldSidebar',
|
19
|
+
'UnfoldThemeConfig',
|
20
|
+
'UnfoldDashboardConfig',
|
21
|
+
|
22
|
+
# Navigation models
|
23
|
+
'NavigationItem',
|
24
|
+
'NavigationSection',
|
25
|
+
'NavigationItemType',
|
26
|
+
|
27
|
+
# Dropdown models
|
28
|
+
'SiteDropdownItem',
|
29
|
+
|
30
|
+
# Dashboard models
|
31
|
+
'StatCard',
|
32
|
+
'SystemHealthItem',
|
33
|
+
'QuickAction',
|
34
|
+
'DashboardWidget',
|
35
|
+
'DashboardData',
|
36
|
+
'ChartDataset',
|
37
|
+
'ChartData',
|
38
|
+
|
39
|
+
# Tab models
|
40
|
+
'TabConfiguration',
|
41
|
+
'TabItem',
|
42
|
+
]
|