django-cfg 1.1.81__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/templates/guide.md +266 -0
- 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.81.dist-info → django_cfg-1.2.0.dist-info}/METADATA +83 -86
- django_cfg-1.2.0.dist-info/RECORD +441 -0
- django_cfg/apps/tasks/@docs/README.md +0 -195
- 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.81.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.81.dist-info → django_cfg-1.2.0.dist-info}/WHEEL +0 -0
- {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,601 @@
|
|
1
|
+
"""
|
2
|
+
Unfold Configuration Models
|
3
|
+
|
4
|
+
Complete configuration models for Django Unfold admin interface.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import List, Optional, Dict, Any, Callable
|
8
|
+
from pydantic import BaseModel, Field, ConfigDict, field_validator
|
9
|
+
from ...base import BaseCfgModule
|
10
|
+
from .navigation import NavigationSection
|
11
|
+
from .dropdown import SiteDropdownItem
|
12
|
+
from .tabs import TabConfiguration
|
13
|
+
from ..icons import Icons
|
14
|
+
import logging
|
15
|
+
|
16
|
+
logger = logging.getLogger(__name__)
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
class UnfoldColors(BaseModel):
|
22
|
+
"""Unfold color theme configuration."""
|
23
|
+
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
24
|
+
|
25
|
+
primary: Optional[str] = Field(None, description="Primary color")
|
26
|
+
success: Optional[str] = Field(None, description="Success color")
|
27
|
+
warning: Optional[str] = Field(None, description="Warning color")
|
28
|
+
danger: Optional[str] = Field(None, description="Danger color")
|
29
|
+
info: Optional[str] = Field(None, description="Info color")
|
30
|
+
|
31
|
+
|
32
|
+
class UnfoldSidebar(BaseModel):
|
33
|
+
"""Unfold sidebar configuration."""
|
34
|
+
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
35
|
+
|
36
|
+
show_search: bool = Field(True, description="Show search in sidebar")
|
37
|
+
show_all_applications: bool = Field(True, description="Show all applications")
|
38
|
+
navigation: List[Dict[str, Any]] = Field(default_factory=list, description="Custom navigation")
|
39
|
+
|
40
|
+
|
41
|
+
class UnfoldTheme(BaseModel):
|
42
|
+
"""Complete Unfold theme configuration."""
|
43
|
+
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
44
|
+
|
45
|
+
# Basic theme settings
|
46
|
+
site_title: str = Field("Django Admin", description="Site title")
|
47
|
+
site_header: str = Field("Django Administration", description="Site header")
|
48
|
+
site_url: str = Field("/", description="Site URL")
|
49
|
+
site_symbol: str = Field(Icons.ROCKET_LAUNCH, description="Material icon for site")
|
50
|
+
|
51
|
+
# UI settings
|
52
|
+
show_history: bool = Field(True, description="Show history in admin")
|
53
|
+
show_view_on_site: bool = Field(True, description="Show view on site links")
|
54
|
+
show_back_button: bool = Field(False, description="Show back button")
|
55
|
+
|
56
|
+
# Theme and appearance
|
57
|
+
theme: Optional[str] = Field(None, description="Theme: light, dark, or None for switcher")
|
58
|
+
colors: UnfoldColors = Field(default_factory=UnfoldColors, description="Color theme")
|
59
|
+
sidebar: UnfoldSidebar = Field(default_factory=UnfoldSidebar, description="Sidebar config")
|
60
|
+
|
61
|
+
# Dashboard
|
62
|
+
dashboard_callback: Optional[str] = Field(None, description="Dashboard callback function")
|
63
|
+
environment_callback: Optional[str] = Field(None, description="Environment callback function")
|
64
|
+
|
65
|
+
# Navigation
|
66
|
+
navigation: List[NavigationSection] = Field(default_factory=list, description="Custom navigation")
|
67
|
+
|
68
|
+
# Site dropdown menu
|
69
|
+
site_dropdown: List[SiteDropdownItem] = Field(default_factory=list, description="Site dropdown menu items")
|
70
|
+
|
71
|
+
def to_django_settings(self) -> Dict[str, Any]:
|
72
|
+
"""Convert to Django UNFOLD settings."""
|
73
|
+
# Try to import colors, fallback to base colors if not available
|
74
|
+
try:
|
75
|
+
from ..tailwind import get_unfold_colors
|
76
|
+
colors = get_unfold_colors()
|
77
|
+
except ImportError:
|
78
|
+
colors = {
|
79
|
+
"primary": {
|
80
|
+
"500": "59, 130, 246",
|
81
|
+
},
|
82
|
+
"base": {
|
83
|
+
"500": "107, 114, 128",
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
settings = {
|
88
|
+
"SITE_TITLE": self.site_title,
|
89
|
+
"SITE_HEADER": self.site_header,
|
90
|
+
"SITE_URL": self.site_url,
|
91
|
+
"SITE_SYMBOL": self.site_symbol,
|
92
|
+
"SHOW_HISTORY": self.show_history,
|
93
|
+
"SHOW_VIEW_ON_SITE": self.show_view_on_site,
|
94
|
+
"SHOW_BACK_BUTTON": self.show_back_button,
|
95
|
+
"COLORS": colors,
|
96
|
+
"BORDER_RADIUS": "8px",
|
97
|
+
}
|
98
|
+
|
99
|
+
# Theme settings
|
100
|
+
if self.theme:
|
101
|
+
settings["THEME"] = self.theme
|
102
|
+
|
103
|
+
# Sidebar configuration - KEY PART!
|
104
|
+
sidebar_config = {
|
105
|
+
"show_search": self.sidebar.show_search,
|
106
|
+
"command_search": True,
|
107
|
+
"show_all_applications": self.sidebar.show_all_applications,
|
108
|
+
}
|
109
|
+
|
110
|
+
# Start with custom navigation from project (if defined)
|
111
|
+
nav_items = []
|
112
|
+
if self.navigation:
|
113
|
+
# Project has custom navigation - add it first
|
114
|
+
nav_items.extend([group.to_dict() for group in self.navigation])
|
115
|
+
|
116
|
+
# Add default navigation from dashboard manager
|
117
|
+
try:
|
118
|
+
from ..dashboard import DashboardManager
|
119
|
+
dashboard = DashboardManager()
|
120
|
+
default_nav_items = dashboard.get_navigation_config()
|
121
|
+
nav_items.extend(default_nav_items)
|
122
|
+
except ImportError:
|
123
|
+
pass
|
124
|
+
|
125
|
+
sidebar_config["navigation"] = nav_items
|
126
|
+
settings["SIDEBAR"] = sidebar_config
|
127
|
+
|
128
|
+
# Command interface
|
129
|
+
settings["COMMAND"] = {
|
130
|
+
"search_models": True,
|
131
|
+
"show_history": True,
|
132
|
+
}
|
133
|
+
|
134
|
+
# Multi-language support - DISABLED
|
135
|
+
settings["SHOW_LANGUAGES"] = False
|
136
|
+
|
137
|
+
# Site dropdown menu
|
138
|
+
if self.site_dropdown:
|
139
|
+
settings["SITE_DROPDOWN"] = [item.to_dict() for item in self.site_dropdown]
|
140
|
+
|
141
|
+
# Dashboard callback
|
142
|
+
if self.dashboard_callback:
|
143
|
+
settings["DASHBOARD_CALLBACK"] = self.dashboard_callback
|
144
|
+
|
145
|
+
# Environment callback
|
146
|
+
if self.environment_callback:
|
147
|
+
settings["ENVIRONMENT_CALLBACK"] = self.environment_callback
|
148
|
+
|
149
|
+
return settings
|
150
|
+
|
151
|
+
|
152
|
+
class UnfoldThemeConfig(UnfoldTheme):
|
153
|
+
"""Unfold theme configuration."""
|
154
|
+
pass
|
155
|
+
|
156
|
+
|
157
|
+
class UnfoldConfig(BaseModel):
|
158
|
+
"""
|
159
|
+
🎨 Unfold Configuration - Django Unfold admin interface
|
160
|
+
|
161
|
+
Complete configuration for Django Unfold admin with dashboard,
|
162
|
+
navigation, theming, and callback support.
|
163
|
+
"""
|
164
|
+
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
165
|
+
|
166
|
+
# Site branding
|
167
|
+
site_title: str = Field(
|
168
|
+
default="ConfigToolkit Admin",
|
169
|
+
description="Site title shown in admin"
|
170
|
+
)
|
171
|
+
|
172
|
+
site_header: str = Field(
|
173
|
+
default="Django Config Toolkit",
|
174
|
+
description="Site header text"
|
175
|
+
)
|
176
|
+
|
177
|
+
site_subheader: str = Field(
|
178
|
+
default="🚀 Type-safe Django Configuration",
|
179
|
+
description="Site subheader text"
|
180
|
+
)
|
181
|
+
|
182
|
+
site_symbol: str = Field(
|
183
|
+
default="settings",
|
184
|
+
description="Material icon symbol for site"
|
185
|
+
)
|
186
|
+
|
187
|
+
site_url: str = Field(
|
188
|
+
default="/",
|
189
|
+
description="Site URL"
|
190
|
+
)
|
191
|
+
|
192
|
+
# UI settings
|
193
|
+
show_history: bool = Field(
|
194
|
+
default=True,
|
195
|
+
description="Show history in admin"
|
196
|
+
)
|
197
|
+
|
198
|
+
show_view_on_site: bool = Field(
|
199
|
+
default=True,
|
200
|
+
description="Show 'View on site' links"
|
201
|
+
)
|
202
|
+
|
203
|
+
show_back_button: bool = Field(
|
204
|
+
default=False,
|
205
|
+
description="Show back button in admin"
|
206
|
+
)
|
207
|
+
|
208
|
+
# Theme settings
|
209
|
+
theme: Optional[str] = Field(
|
210
|
+
default=None,
|
211
|
+
description="Theme setting (light/dark/auto)"
|
212
|
+
)
|
213
|
+
|
214
|
+
border_radius: str = Field(
|
215
|
+
default="8px",
|
216
|
+
description="Border radius for UI elements"
|
217
|
+
)
|
218
|
+
|
219
|
+
# Dashboard settings
|
220
|
+
dashboard_enabled: bool = Field(
|
221
|
+
default=True,
|
222
|
+
description="Enable custom dashboard"
|
223
|
+
)
|
224
|
+
|
225
|
+
dashboard_callback: Optional[str] = Field(
|
226
|
+
default="django_cfg.routing.callbacks.dashboard_callback",
|
227
|
+
description="Dashboard callback function path"
|
228
|
+
)
|
229
|
+
|
230
|
+
environment_callback: Optional[str] = Field(
|
231
|
+
default="django_cfg.routing.callbacks.environment_callback",
|
232
|
+
description="Environment callback function path"
|
233
|
+
)
|
234
|
+
|
235
|
+
# Navigation settings
|
236
|
+
show_search: bool = Field(
|
237
|
+
default=True,
|
238
|
+
description="Show search in sidebar"
|
239
|
+
)
|
240
|
+
|
241
|
+
command_search: bool = Field(
|
242
|
+
default=True,
|
243
|
+
description="Enable command search"
|
244
|
+
)
|
245
|
+
|
246
|
+
show_all_applications: bool = Field(
|
247
|
+
default=True,
|
248
|
+
description="Show all applications in sidebar"
|
249
|
+
)
|
250
|
+
|
251
|
+
# Multi-language settings
|
252
|
+
show_languages: bool = Field(
|
253
|
+
default=False,
|
254
|
+
description="Show language switcher"
|
255
|
+
)
|
256
|
+
|
257
|
+
# Colors configuration
|
258
|
+
colors: Optional[UnfoldColors] = Field(
|
259
|
+
default=None,
|
260
|
+
description="Color theme configuration"
|
261
|
+
)
|
262
|
+
|
263
|
+
# Sidebar configuration
|
264
|
+
sidebar: Optional[UnfoldSidebar] = Field(
|
265
|
+
default=None,
|
266
|
+
description="Sidebar configuration"
|
267
|
+
)
|
268
|
+
|
269
|
+
# Navigation items
|
270
|
+
navigation: List[NavigationSection] = Field(
|
271
|
+
default_factory=list,
|
272
|
+
description="Custom navigation sections"
|
273
|
+
)
|
274
|
+
|
275
|
+
navigation_items: List[Dict[str, Any]] = Field(
|
276
|
+
default_factory=list,
|
277
|
+
description="Custom navigation items (legacy)"
|
278
|
+
)
|
279
|
+
|
280
|
+
# Site dropdown items
|
281
|
+
site_dropdown: List[SiteDropdownItem] = Field(
|
282
|
+
default_factory=list,
|
283
|
+
description="Site dropdown menu items"
|
284
|
+
)
|
285
|
+
|
286
|
+
site_dropdown_items: List[Dict[str, Any]] = Field(
|
287
|
+
default_factory=list,
|
288
|
+
description="Site dropdown menu items (legacy)"
|
289
|
+
)
|
290
|
+
|
291
|
+
# Tab configurations
|
292
|
+
tab_configurations: List[Dict[str, Any]] = Field(
|
293
|
+
default_factory=list,
|
294
|
+
description="Tab configurations for admin"
|
295
|
+
)
|
296
|
+
|
297
|
+
@field_validator('theme')
|
298
|
+
@classmethod
|
299
|
+
def validate_theme(cls, v: Optional[str]) -> Optional[str]:
|
300
|
+
"""Validate theme setting."""
|
301
|
+
if v and v not in ['light', 'dark', 'auto']:
|
302
|
+
raise ValueError("Theme must be 'light', 'dark', 'auto', or None")
|
303
|
+
return v
|
304
|
+
|
305
|
+
def get_color_scheme(self) -> Dict[str, Any]:
|
306
|
+
"""Get Unfold semantic color scheme configuration with theme support."""
|
307
|
+
return {
|
308
|
+
# Base semantic colors that auto-adapt to theme
|
309
|
+
"base": {
|
310
|
+
"50": "248, 250, 252", # Light theme: very light background
|
311
|
+
"100": "241, 245, 249", # Light theme: light background
|
312
|
+
"200": "226, 232, 240", # Light theme: subtle border
|
313
|
+
"300": "203, 213, 225", # Light theme: border
|
314
|
+
"400": "148, 163, 184", # Light theme: muted text / Dark theme: text
|
315
|
+
"500": "100, 116, 139", # Neutral - works in both themes
|
316
|
+
"600": "71, 85, 105", # Dark theme: muted text / Light theme: text
|
317
|
+
"700": "51, 65, 85", # Dark theme: border
|
318
|
+
"800": "30, 41, 59", # Dark theme: subtle border
|
319
|
+
"900": "15, 23, 42", # Dark theme: light background
|
320
|
+
"950": "2, 6, 23", # Dark theme: very light background
|
321
|
+
},
|
322
|
+
# Primary brand - auto-adapts via CSS variables
|
323
|
+
"primary": {
|
324
|
+
"50": "239, 246, 255",
|
325
|
+
"100": "219, 234, 254",
|
326
|
+
"200": "191, 219, 254",
|
327
|
+
"300": "147, 197, 253",
|
328
|
+
"400": "96, 165, 250",
|
329
|
+
"500": "59, 130, 246", # Main brand color
|
330
|
+
"600": "37, 99, 235",
|
331
|
+
"700": "29, 78, 216",
|
332
|
+
"800": "30, 64, 175",
|
333
|
+
"900": "30, 58, 138",
|
334
|
+
"950": "23, 37, 84",
|
335
|
+
},
|
336
|
+
# Success semantic color
|
337
|
+
"success": {
|
338
|
+
"50": "236, 253, 245",
|
339
|
+
"100": "209, 250, 229",
|
340
|
+
"200": "167, 243, 208",
|
341
|
+
"300": "110, 231, 183",
|
342
|
+
"400": "52, 211, 153",
|
343
|
+
"500": "16, 185, 129", # Main success color
|
344
|
+
"600": "5, 150, 105",
|
345
|
+
"700": "4, 120, 87",
|
346
|
+
"800": "6, 95, 70",
|
347
|
+
"900": "6, 78, 59",
|
348
|
+
"950": "2, 44, 34",
|
349
|
+
},
|
350
|
+
# Warning semantic color
|
351
|
+
"warning": {
|
352
|
+
"50": "255, 251, 235",
|
353
|
+
"100": "254, 243, 199",
|
354
|
+
"200": "253, 230, 138",
|
355
|
+
"300": "252, 211, 77",
|
356
|
+
"400": "251, 191, 36",
|
357
|
+
"500": "245, 158, 11", # Main warning color
|
358
|
+
"600": "217, 119, 6",
|
359
|
+
"700": "180, 83, 9",
|
360
|
+
"800": "146, 64, 14",
|
361
|
+
"900": "120, 53, 15",
|
362
|
+
"950": "69, 26, 3",
|
363
|
+
},
|
364
|
+
# Danger semantic color
|
365
|
+
"danger": {
|
366
|
+
"50": "254, 242, 242",
|
367
|
+
"100": "254, 226, 226",
|
368
|
+
"200": "254, 202, 202",
|
369
|
+
"300": "252, 165, 165",
|
370
|
+
"400": "248, 113, 113",
|
371
|
+
"500": "239, 68, 68", # Main danger color
|
372
|
+
"600": "220, 38, 38",
|
373
|
+
"700": "185, 28, 28",
|
374
|
+
"800": "153, 27, 27",
|
375
|
+
"900": "127, 29, 29",
|
376
|
+
"950": "69, 10, 10",
|
377
|
+
},
|
378
|
+
# Info semantic color
|
379
|
+
"info": {
|
380
|
+
"50": "236, 254, 255",
|
381
|
+
"100": "207, 250, 254",
|
382
|
+
"200": "165, 243, 252",
|
383
|
+
"300": "103, 232, 249",
|
384
|
+
"400": "34, 211, 238",
|
385
|
+
"500": "6, 182, 212", # Main info color
|
386
|
+
"600": "8, 145, 178",
|
387
|
+
"700": "14, 116, 144",
|
388
|
+
"800": "21, 94, 117",
|
389
|
+
"900": "22, 78, 99",
|
390
|
+
"950": "8, 51, 68",
|
391
|
+
},
|
392
|
+
}
|
393
|
+
|
394
|
+
def to_django_settings(self) -> Dict[str, Any]:
|
395
|
+
"""Generate Django settings for Unfold."""
|
396
|
+
# Base Unfold configuration
|
397
|
+
unfold_settings = {
|
398
|
+
"SITE_TITLE": self.site_title,
|
399
|
+
"SITE_HEADER": self.site_header,
|
400
|
+
"SITE_SUBHEADER": self.site_subheader,
|
401
|
+
"SITE_URL": self.site_url,
|
402
|
+
"SITE_SYMBOL": self.site_symbol,
|
403
|
+
"SHOW_HISTORY": self.show_history,
|
404
|
+
"SHOW_VIEW_ON_SITE": self.show_view_on_site,
|
405
|
+
"SHOW_BACK_BUTTON": self.show_back_button,
|
406
|
+
"THEME": self.theme,
|
407
|
+
"BORDER_RADIUS": self.border_radius,
|
408
|
+
"SHOW_LANGUAGES": self.show_languages,
|
409
|
+
"COLORS": self.get_color_scheme(),
|
410
|
+
}
|
411
|
+
|
412
|
+
# Add callbacks if configured
|
413
|
+
if self.dashboard_callback:
|
414
|
+
unfold_settings["DASHBOARD_CALLBACK"] = self.dashboard_callback
|
415
|
+
|
416
|
+
if self.environment_callback:
|
417
|
+
unfold_settings["ENVIRONMENT"] = self.environment_callback
|
418
|
+
|
419
|
+
# Sidebar configuration
|
420
|
+
sidebar_config = {
|
421
|
+
"show_search": self.show_search,
|
422
|
+
"command_search": self.command_search,
|
423
|
+
"show_all_applications": self.show_all_applications,
|
424
|
+
}
|
425
|
+
|
426
|
+
# Get default navigation from dashboard manager
|
427
|
+
try:
|
428
|
+
from ..dashboard import DashboardManager
|
429
|
+
dashboard = DashboardManager()
|
430
|
+
nav_items = dashboard.get_navigation_config()
|
431
|
+
except ImportError:
|
432
|
+
nav_items = []
|
433
|
+
|
434
|
+
# Add custom navigation from project (if defined)
|
435
|
+
if self.navigation:
|
436
|
+
# Project has custom navigation - add it first
|
437
|
+
nav_items.extend([group.to_dict() for group in self.navigation])
|
438
|
+
|
439
|
+
# Add legacy navigation_items if configured
|
440
|
+
if self.navigation_items:
|
441
|
+
nav_items.extend(self.navigation_items)
|
442
|
+
|
443
|
+
sidebar_config["navigation"] = nav_items
|
444
|
+
unfold_settings["SIDEBAR"] = sidebar_config
|
445
|
+
|
446
|
+
# Add site dropdown - combine default from dashboard + project dropdown
|
447
|
+
dropdown_items = []
|
448
|
+
|
449
|
+
# First add default dropdown from dashboard manager
|
450
|
+
try:
|
451
|
+
from ..dashboard import DashboardManager
|
452
|
+
dashboard = DashboardManager()
|
453
|
+
dropdown_items.extend(dashboard._get_default_dropdown_items())
|
454
|
+
except ImportError:
|
455
|
+
pass
|
456
|
+
|
457
|
+
# Then add project-specific dropdown items
|
458
|
+
if self.site_dropdown:
|
459
|
+
dropdown_items.extend([item.to_dict() for item in self.site_dropdown])
|
460
|
+
elif self.site_dropdown_items:
|
461
|
+
dropdown_items.extend(self.site_dropdown_items)
|
462
|
+
|
463
|
+
if dropdown_items:
|
464
|
+
unfold_settings["SITE_DROPDOWN"] = dropdown_items
|
465
|
+
|
466
|
+
# Add tabs if configured
|
467
|
+
if self.tab_configurations:
|
468
|
+
unfold_settings["TABS"] = self.tab_configurations
|
469
|
+
|
470
|
+
# Command interface
|
471
|
+
unfold_settings["COMMAND"] = {
|
472
|
+
"search_models": True,
|
473
|
+
"show_history": True,
|
474
|
+
}
|
475
|
+
|
476
|
+
# Inject universal CSS variables (includes object-tools flex)
|
477
|
+
if "STYLES" not in unfold_settings:
|
478
|
+
unfold_settings["STYLES"] = []
|
479
|
+
|
480
|
+
# Add our CSS as inline data URI
|
481
|
+
try:
|
482
|
+
from ..tailwind import get_css_variables
|
483
|
+
import base64
|
484
|
+
css_content = get_css_variables()
|
485
|
+
css_b64 = base64.b64encode(css_content.encode('utf-8')).decode('utf-8')
|
486
|
+
data_uri = f"data:text/css;base64,{css_b64}"
|
487
|
+
unfold_settings["STYLES"].append(lambda request: data_uri)
|
488
|
+
except ImportError:
|
489
|
+
pass
|
490
|
+
|
491
|
+
return {"UNFOLD": unfold_settings}
|
492
|
+
|
493
|
+
|
494
|
+
class UnfoldDashboardConfig(BaseModel):
|
495
|
+
"""Complete Unfold dashboard configuration."""
|
496
|
+
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
497
|
+
|
498
|
+
# Site branding
|
499
|
+
site_title: str = Field(default="Admin Dashboard", description="Site title")
|
500
|
+
site_header: str = Field(default="Admin", description="Site header")
|
501
|
+
site_subheader: str = Field(default="Management Interface", description="Site subheader")
|
502
|
+
site_url: str = Field(default="/", description="Site URL")
|
503
|
+
site_symbol: str = Field(default=Icons.ADMIN_PANEL_SETTINGS, description="Site icon")
|
504
|
+
|
505
|
+
# UI settings
|
506
|
+
show_history: bool = Field(default=True, description="Show history")
|
507
|
+
show_view_on_site: bool = Field(default=True, description="Show view on site")
|
508
|
+
show_back_button: bool = Field(default=False, description="Show back button")
|
509
|
+
theme: Optional[str] = Field(default=None, description="Theme (light/dark) or None for theme switcher")
|
510
|
+
show_languages: bool = Field(default=False, description="Show language switcher")
|
511
|
+
show_theme_switcher: bool = Field(default=True, description="Show theme switcher (requires theme=None)")
|
512
|
+
|
513
|
+
# Callbacks
|
514
|
+
dashboard_callback: Optional[str] = Field(None, description="Dashboard callback path")
|
515
|
+
environment_callback: Optional[str] = Field(None, description="Environment callback path")
|
516
|
+
|
517
|
+
# Navigation configuration
|
518
|
+
navigation_sections: List[NavigationSection] = Field(
|
519
|
+
default_factory=list,
|
520
|
+
description="Navigation sections"
|
521
|
+
)
|
522
|
+
|
523
|
+
# Site dropdown configuration
|
524
|
+
site_dropdown_items: List[SiteDropdownItem] = Field(
|
525
|
+
default_factory=list,
|
526
|
+
description="Site dropdown items"
|
527
|
+
)
|
528
|
+
|
529
|
+
# Tab configurations
|
530
|
+
tab_configurations: List[TabConfiguration] = Field(
|
531
|
+
default_factory=list,
|
532
|
+
description="Tab configurations"
|
533
|
+
)
|
534
|
+
|
535
|
+
def to_unfold_dict(self) -> Dict[str, Any]:
|
536
|
+
"""Convert to Unfold configuration dictionary."""
|
537
|
+
base_config = {
|
538
|
+
"SITE_TITLE": self.site_title,
|
539
|
+
"SITE_HEADER": self.site_header,
|
540
|
+
"SITE_SUBHEADER": self.site_subheader,
|
541
|
+
"SITE_URL": self.site_url,
|
542
|
+
"SITE_SYMBOL": self.site_symbol,
|
543
|
+
"SHOW_HISTORY": self.show_history,
|
544
|
+
"SHOW_VIEW_ON_SITE": self.show_view_on_site,
|
545
|
+
"SHOW_BACK_BUTTON": self.show_back_button,
|
546
|
+
"SHOW_LANGUAGES": self.show_languages,
|
547
|
+
}
|
548
|
+
|
549
|
+
# Theme configuration: None enables theme switcher, string value forces theme
|
550
|
+
if self.show_theme_switcher and self.theme is None:
|
551
|
+
# Don't set THEME key - this enables theme switcher
|
552
|
+
pass
|
553
|
+
else:
|
554
|
+
# Set specific theme - this disables theme switcher
|
555
|
+
base_config["THEME"] = self.theme
|
556
|
+
|
557
|
+
# Add callbacks if configured
|
558
|
+
if self.dashboard_callback:
|
559
|
+
base_config["DASHBOARD_CALLBACK"] = self.dashboard_callback
|
560
|
+
|
561
|
+
if self.environment_callback:
|
562
|
+
base_config["ENVIRONMENT"] = self.environment_callback
|
563
|
+
|
564
|
+
# Sidebar configuration
|
565
|
+
sidebar_config = {
|
566
|
+
"show_search": True,
|
567
|
+
"command_search": True,
|
568
|
+
"show_all_applications": True,
|
569
|
+
}
|
570
|
+
|
571
|
+
# Convert navigation sections
|
572
|
+
if self.navigation_sections:
|
573
|
+
sidebar_config["navigation"] = [section.to_dict() for section in self.navigation_sections]
|
574
|
+
|
575
|
+
base_config["SIDEBAR"] = sidebar_config
|
576
|
+
|
577
|
+
# Convert site dropdown
|
578
|
+
if self.site_dropdown_items:
|
579
|
+
base_config["SITE_DROPDOWN"] = [item.to_dict() for item in self.site_dropdown_items]
|
580
|
+
|
581
|
+
# Convert tabs
|
582
|
+
if self.tab_configurations:
|
583
|
+
tabs = []
|
584
|
+
for tab in self.tab_configurations:
|
585
|
+
tab_items = []
|
586
|
+
for item in tab.items:
|
587
|
+
tab_item = {
|
588
|
+
"title": item.title,
|
589
|
+
"link": item.get_link_for_unfold() if hasattr(item, 'get_link_for_unfold') else item.link,
|
590
|
+
}
|
591
|
+
if item.permission:
|
592
|
+
tab_item["permission"] = item.permission
|
593
|
+
tab_items.append(tab_item)
|
594
|
+
|
595
|
+
tabs.append({
|
596
|
+
"models": tab.models,
|
597
|
+
"items": tab_items,
|
598
|
+
})
|
599
|
+
base_config["TABS"] = tabs
|
600
|
+
|
601
|
+
return base_config
|