django-cfg 1.4.13__py3-none-any.whl → 1.4.15__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/apps/urls.py +120 -108
- django_cfg/core/integration/url_integration.py +5 -10
- django_cfg/models/django/openapi.py +11 -48
- django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +10 -10
- django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +23 -20
- django_cfg/modules/django_client/core/generator/typescript/models_generator.py +13 -9
- django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +3 -6
- django_cfg/modules/django_unfold/dashboard.py +6 -6
- django_cfg/pyproject.toml +1 -1
- {django_cfg-1.4.13.dist-info → django_cfg-1.4.15.dist-info}/METADATA +1 -1
- {django_cfg-1.4.13.dist-info → django_cfg-1.4.15.dist-info}/RECORD +14 -21
- django_cfg/modules/django_dashboard/DEBUG_README.md +0 -105
- django_cfg/modules/django_dashboard/REFACTORING_SUMMARY.md +0 -237
- django_cfg/modules/django_drf_theme/CHANGELOG.md +0 -210
- django_cfg/modules/django_drf_theme/EXAMPLE.md +0 -465
- django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +0 -232
- django_cfg/modules/django_drf_theme/README.md +0 -207
- django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +0 -274
- {django_cfg-1.4.13.dist-info → django_cfg-1.4.15.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.13.dist-info → django_cfg-1.4.15.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.13.dist-info → django_cfg-1.4.15.dist-info}/licenses/LICENSE +0 -0
django_cfg/apps/urls.py
CHANGED
@@ -5,130 +5,142 @@ Built-in API endpoints for django_cfg functionality.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
from django.urls import path, include
|
8
|
-
from typing import List
|
9
|
-
from django.urls import URLPattern
|
8
|
+
from typing import List
|
10
9
|
|
11
10
|
|
12
|
-
def
|
11
|
+
def get_enabled_cfg_apps() -> List[str]:
|
13
12
|
"""
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
Args:
|
19
|
-
patterns: URL patterns list to append to
|
20
|
-
groups: OpenAPI groups dict
|
21
|
-
"""
|
22
|
-
for group_name in groups.keys():
|
23
|
-
# Only django-cfg apps (convention: cfg_*)
|
24
|
-
if not group_name.startswith('cfg_'):
|
25
|
-
continue
|
26
|
-
|
27
|
-
# Extract app name: cfg_payments → payments
|
28
|
-
app_name = group_name[4:]
|
29
|
-
|
30
|
-
# Register main URLs: /cfg/{app}/
|
31
|
-
try:
|
32
|
-
patterns.append(
|
33
|
-
path(f'cfg/{app_name}/', include(f'django_cfg.apps.{app_name}.urls'))
|
34
|
-
)
|
35
|
-
except ImportError:
|
36
|
-
pass # URL module doesn't exist
|
37
|
-
|
38
|
-
# Register admin URLs: /cfg/{app}/admin/ (if exists)
|
39
|
-
try:
|
40
|
-
patterns.append(
|
41
|
-
path(f'cfg/{app_name}/admin/', include(f'django_cfg.apps.{app_name}.urls_admin'))
|
42
|
-
)
|
43
|
-
except ImportError:
|
44
|
-
pass # Admin URL module doesn't exist
|
45
|
-
|
46
|
-
|
47
|
-
def _register_apps_fallback(patterns: List[URLPattern]) -> None:
|
48
|
-
"""
|
49
|
-
Fallback: Register apps when OpenAPI is disabled.
|
50
|
-
|
51
|
-
Uses BaseCfgModule checks to determine which apps are enabled.
|
52
|
-
|
53
|
-
Args:
|
54
|
-
patterns: URL patterns list to append to
|
13
|
+
Get list of enabled django-cfg apps based on configuration.
|
14
|
+
|
15
|
+
Returns:
|
16
|
+
List of enabled app paths (e.g., ['django_cfg.apps.accounts', ...])
|
55
17
|
"""
|
56
18
|
from django_cfg.modules.base import BaseCfgModule
|
19
|
+
|
57
20
|
base_module = BaseCfgModule()
|
58
|
-
|
59
|
-
|
60
|
-
if base_module.is_support_enabled():
|
61
|
-
patterns.append(path('cfg/support/', include('django_cfg.apps.support.urls')))
|
62
|
-
|
21
|
+
enabled_apps = []
|
22
|
+
|
63
23
|
if base_module.is_accounts_enabled():
|
64
|
-
|
65
|
-
|
24
|
+
enabled_apps.append("django_cfg.apps.accounts")
|
25
|
+
|
26
|
+
if base_module.is_support_enabled():
|
27
|
+
enabled_apps.append("django_cfg.apps.support")
|
28
|
+
|
66
29
|
if base_module.is_newsletter_enabled():
|
67
|
-
|
68
|
-
|
30
|
+
enabled_apps.append("django_cfg.apps.newsletter")
|
31
|
+
|
69
32
|
if base_module.is_leads_enabled():
|
70
|
-
|
71
|
-
|
33
|
+
enabled_apps.append("django_cfg.apps.leads")
|
34
|
+
|
72
35
|
if base_module.is_knowbase_enabled():
|
73
|
-
|
74
|
-
|
36
|
+
enabled_apps.append("django_cfg.apps.knowbase")
|
37
|
+
|
75
38
|
if base_module.is_agents_enabled():
|
76
|
-
|
77
|
-
|
39
|
+
enabled_apps.append("django_cfg.apps.agents")
|
40
|
+
|
78
41
|
if base_module.should_enable_tasks():
|
79
|
-
|
80
|
-
|
81
|
-
|
42
|
+
enabled_apps.append("django_cfg.apps.tasks")
|
43
|
+
|
82
44
|
if base_module.is_payments_enabled():
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
# Standalone apps
|
87
|
-
if base_module.is_maintenance_enabled():
|
88
|
-
patterns.append(
|
89
|
-
path('admin/django_cfg_maintenance/', include('django_cfg.apps.maintenance.urls_admin'))
|
90
|
-
)
|
91
|
-
|
92
|
-
if base_module.is_rpc_enabled():
|
93
|
-
patterns.append(path('rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls')))
|
94
|
-
patterns.append(path('admin/rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls_admin')))
|
45
|
+
enabled_apps.append("django_cfg.apps.payments")
|
46
|
+
|
47
|
+
return enabled_apps
|
95
48
|
|
96
49
|
|
97
|
-
def
|
50
|
+
def get_default_cfg_group():
|
98
51
|
"""
|
99
|
-
|
100
|
-
|
52
|
+
Returns default OpenAPIGroupConfig for enabled django-cfg apps.
|
53
|
+
|
54
|
+
Only includes apps that are enabled in the current configuration.
|
55
|
+
|
56
|
+
This can be imported and added to your project's OpenAPIClientConfig groups:
|
57
|
+
|
58
|
+
```python
|
59
|
+
from django_cfg.apps.urls import get_default_cfg_group
|
60
|
+
|
61
|
+
openapi_client = OpenAPIClientConfig(
|
62
|
+
groups=[
|
63
|
+
get_default_cfg_group(),
|
64
|
+
# ... your custom groups
|
65
|
+
]
|
66
|
+
)
|
67
|
+
```
|
68
|
+
|
101
69
|
Returns:
|
102
|
-
|
70
|
+
OpenAPIGroupConfig with enabled django-cfg apps
|
103
71
|
"""
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
72
|
+
from django_cfg.modules.django_client.core.config import OpenAPIGroupConfig
|
73
|
+
|
74
|
+
return OpenAPIGroupConfig(
|
75
|
+
name="cfg",
|
76
|
+
apps=get_enabled_cfg_apps(),
|
77
|
+
title="Django-CFG API",
|
78
|
+
description="Authentication (OTP), Support, Newsletter, Leads, Knowledge Base, AI Agents, Tasks, Payments",
|
79
|
+
version="1.0.0",
|
80
|
+
)
|
81
|
+
|
82
|
+
|
83
|
+
def _safe_include(pattern_path: str, module_path: str):
|
84
|
+
"""Helper to safely include URL module if it exists."""
|
115
85
|
try:
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
86
|
+
return path(pattern_path, include(module_path))
|
87
|
+
except ImportError:
|
88
|
+
return None
|
89
|
+
|
90
|
+
|
91
|
+
# Core API endpoints (always enabled)
|
92
|
+
# Note: All prefixes are explicit here (cfg/, health/, etc.)
|
93
|
+
urlpatterns = [
|
94
|
+
path('cfg/health/', include('django_cfg.apps.api.health.urls')),
|
95
|
+
path('cfg/endpoints/', include('django_cfg.apps.api.endpoints.urls')),
|
96
|
+
path('cfg/commands/', include('django_cfg.apps.api.commands.urls')),
|
97
|
+
path('cfg/openapi/', include('django_cfg.modules.django_client.urls')),
|
98
|
+
]
|
99
|
+
|
100
|
+
# Django-CFG apps - conditionally registered based on config
|
101
|
+
# Map app paths to URL patterns (with cfg/ prefix from add_django_cfg_urls)
|
102
|
+
APP_URL_MAP = {
|
103
|
+
"django_cfg.apps.accounts": [
|
104
|
+
("cfg/accounts/", "django_cfg.apps.accounts.urls"),
|
105
|
+
],
|
106
|
+
"django_cfg.apps.support": [
|
107
|
+
("cfg/support/", "django_cfg.apps.support.urls"),
|
108
|
+
],
|
109
|
+
"django_cfg.apps.newsletter": [
|
110
|
+
("cfg/newsletter/", "django_cfg.apps.newsletter.urls"),
|
111
|
+
],
|
112
|
+
"django_cfg.apps.leads": [
|
113
|
+
("cfg/leads/", "django_cfg.apps.leads.urls"),
|
114
|
+
],
|
115
|
+
"django_cfg.apps.knowbase": [
|
116
|
+
("cfg/knowbase/", "django_cfg.apps.knowbase.urls"),
|
117
|
+
],
|
118
|
+
"django_cfg.apps.agents": [
|
119
|
+
("cfg/agents/", "django_cfg.apps.agents.urls"),
|
120
|
+
],
|
121
|
+
"django_cfg.apps.tasks": [
|
122
|
+
("cfg/tasks/", "django_cfg.apps.tasks.urls"),
|
123
|
+
("cfg/tasks/admin/", "django_cfg.apps.tasks.urls_admin"),
|
124
|
+
],
|
125
|
+
"django_cfg.apps.payments": [
|
126
|
+
("cfg/payments/", "django_cfg.apps.payments.urls"),
|
127
|
+
("cfg/payments/admin/", "django_cfg.apps.payments.urls_admin"),
|
128
|
+
],
|
129
|
+
}
|
130
|
+
|
131
|
+
# Register URLs for enabled apps only
|
132
|
+
enabled_apps = get_enabled_cfg_apps()
|
133
|
+
cfg_app_urls = []
|
134
|
+
|
135
|
+
for app_path in enabled_apps:
|
136
|
+
if app_path in APP_URL_MAP:
|
137
|
+
for url_pattern, url_module in APP_URL_MAP[app_path]:
|
138
|
+
cfg_app_urls.append(_safe_include(url_pattern, url_module))
|
139
|
+
|
140
|
+
# Maintenance (special case - admin only)
|
141
|
+
from django_cfg.modules.base import BaseCfgModule
|
142
|
+
if BaseCfgModule().is_maintenance_enabled():
|
143
|
+
cfg_app_urls.append(_safe_include('admin/django_cfg_maintenance/', 'django_cfg.apps.maintenance.urls_admin'))
|
144
|
+
|
145
|
+
# Add only successfully imported URLs
|
146
|
+
urlpatterns.extend([url for url in cfg_app_urls if url is not None])
|
@@ -10,18 +10,17 @@ from django_cfg.core.environment import EnvironmentDetector
|
|
10
10
|
from django.conf import settings
|
11
11
|
|
12
12
|
|
13
|
-
def add_django_cfg_urls(urlpatterns: List[URLPattern]
|
13
|
+
def add_django_cfg_urls(urlpatterns: List[URLPattern]) -> List[URLPattern]:
|
14
14
|
"""
|
15
15
|
Automatically add django_cfg URLs and all integrations to the main URL configuration.
|
16
16
|
|
17
17
|
This function adds:
|
18
|
-
- Django CFG management URLs
|
18
|
+
- Django CFG management URLs
|
19
19
|
- Django Client URLs (if available)
|
20
20
|
- Startup information display (based on config)
|
21
21
|
|
22
22
|
Args:
|
23
23
|
urlpatterns: Existing URL patterns list
|
24
|
-
cfg_prefix: URL prefix for django_cfg endpoints (default: "cfg/")
|
25
24
|
|
26
25
|
Returns:
|
27
26
|
Updated URL patterns list with all URLs added
|
@@ -35,17 +34,13 @@ def add_django_cfg_urls(urlpatterns: List[URLPattern], cfg_prefix: str = "cfg/")
|
|
35
34
|
path("admin/", admin.site.urls),
|
36
35
|
]
|
37
36
|
|
38
|
-
# Automatically adds
|
39
|
-
# - path("cfg/", include("django_cfg.apps.urls"))
|
40
|
-
# - Django Client URLs (if available)
|
41
|
-
# - Startup info display (based on config.startup_info_mode)
|
37
|
+
# Automatically adds django_cfg URLs with proper prefixes
|
42
38
|
urlpatterns = add_django_cfg_urls(urlpatterns)
|
43
39
|
"""
|
44
40
|
# Add django_cfg API URLs
|
45
|
-
# Note:
|
46
|
-
# at /cfg/openapi/{group}/schema/ to avoid conflicts
|
41
|
+
# Note: URL prefixes (cfg/, health/, etc.) are defined in django_cfg.apps.urls
|
47
42
|
new_patterns = urlpatterns + [
|
48
|
-
path(
|
43
|
+
path("", include("django_cfg.apps.urls")),
|
49
44
|
]
|
50
45
|
|
51
46
|
# Add django-browser-reload URLs in development (if installed)
|
@@ -57,8 +57,8 @@ class OpenAPIClientConfig(OpenAPIConfig):
|
|
57
57
|
description="Schema path prefix for DRF Spectacular"
|
58
58
|
)
|
59
59
|
drf_enable_browsable_api: bool = Field(
|
60
|
-
default=
|
61
|
-
description="Enable DRF browsable API"
|
60
|
+
default=True,
|
61
|
+
description="Enable DRF browsable API with Tailwind theme"
|
62
62
|
)
|
63
63
|
drf_enable_throttling: bool = Field(
|
64
64
|
default=False,
|
@@ -104,6 +104,8 @@ class OpenAPIClientConfig(OpenAPIConfig):
|
|
104
104
|
def get_groups_with_defaults(self) -> Dict[str, OpenAPIGroupConfig]:
|
105
105
|
"""
|
106
106
|
Get groups with django-cfg default groups automatically added.
|
107
|
+
|
108
|
+
Automatically adds the 'cfg' group with all django-cfg apps if not explicitly defined.
|
107
109
|
|
108
110
|
Returns:
|
109
111
|
Dict of groups including default django-cfg groups
|
@@ -111,52 +113,13 @@ class OpenAPIClientConfig(OpenAPIConfig):
|
|
111
113
|
# Convert list to dict for compatibility
|
112
114
|
groups_dict = {group.name: group for group in self.groups}
|
113
115
|
|
114
|
-
# Add default
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
newsletter_enabled = base_module.is_newsletter_enabled()
|
122
|
-
leads_enabled = base_module.is_leads_enabled()
|
123
|
-
knowbase_enabled = base_module.is_knowbase_enabled()
|
124
|
-
agents_enabled = base_module.is_agents_enabled()
|
125
|
-
tasks_enabled = base_module.should_enable_tasks()
|
126
|
-
payments_enabled = base_module.is_payments_enabled()
|
127
|
-
|
128
|
-
# Collect all enabled django-cfg apps for unified group
|
129
|
-
enabled_cfg_apps = []
|
130
|
-
if support_enabled:
|
131
|
-
enabled_cfg_apps.append("django_cfg.apps.support")
|
132
|
-
if accounts_enabled:
|
133
|
-
enabled_cfg_apps.append("django_cfg.apps.accounts")
|
134
|
-
if newsletter_enabled:
|
135
|
-
enabled_cfg_apps.append("django_cfg.apps.newsletter")
|
136
|
-
if leads_enabled:
|
137
|
-
enabled_cfg_apps.append("django_cfg.apps.leads")
|
138
|
-
if knowbase_enabled:
|
139
|
-
enabled_cfg_apps.append("django_cfg.apps.knowbase")
|
140
|
-
if agents_enabled:
|
141
|
-
enabled_cfg_apps.append("django_cfg.apps.agents")
|
142
|
-
if tasks_enabled:
|
143
|
-
enabled_cfg_apps.append("django_cfg.apps.tasks")
|
144
|
-
if payments_enabled:
|
145
|
-
enabled_cfg_apps.append("django_cfg.apps.payments")
|
146
|
-
|
147
|
-
# Add unified 'cfg' group with all enabled apps
|
148
|
-
if enabled_cfg_apps and 'cfg' not in groups_dict:
|
149
|
-
groups_dict['cfg'] = OpenAPIGroupConfig(
|
150
|
-
name="cfg",
|
151
|
-
apps=enabled_cfg_apps,
|
152
|
-
title="Django-CFG API",
|
153
|
-
description="All django-cfg built-in applications",
|
154
|
-
)
|
155
|
-
|
156
|
-
return groups_dict
|
157
|
-
|
158
|
-
except Exception:
|
159
|
-
pass
|
116
|
+
# Add default 'cfg' group if not explicitly defined
|
117
|
+
if 'cfg' not in groups_dict:
|
118
|
+
try:
|
119
|
+
from django_cfg.apps.urls import get_default_cfg_group
|
120
|
+
groups_dict['cfg'] = get_default_cfg_group()
|
121
|
+
except Exception:
|
122
|
+
pass
|
160
123
|
|
161
124
|
return groups_dict
|
162
125
|
|
@@ -110,24 +110,24 @@ class FetchersGenerator:
|
|
110
110
|
Convert operation to function name.
|
111
111
|
|
112
112
|
Examples:
|
113
|
-
users_list (GET) ->
|
114
|
-
users_retrieve (GET) ->
|
115
|
-
users_create (POST) ->
|
116
|
-
users_update (PUT) ->
|
117
|
-
users_partial_update (PATCH) ->
|
118
|
-
users_destroy (DELETE) ->
|
113
|
+
users_list (GET) -> getUsersList
|
114
|
+
users_retrieve (GET) -> getUsersById
|
115
|
+
users_create (POST) -> createUsers
|
116
|
+
users_update (PUT) -> updateUsers
|
117
|
+
users_partial_update (PATCH) -> partialUpdateUsers
|
118
|
+
users_destroy (DELETE) -> deleteUsers
|
119
119
|
"""
|
120
120
|
# Remove tag prefix from operation_id
|
121
121
|
op_id = operation.operation_id
|
122
122
|
|
123
|
-
# Handle common patterns
|
123
|
+
# Handle common patterns - keep full resource name for uniqueness
|
124
124
|
if op_id.endswith("_list"):
|
125
125
|
resource = op_id.removesuffix("_list")
|
126
|
-
return f"get{self._to_pascal_case(resource)}"
|
126
|
+
return f"get{self._to_pascal_case(resource)}List"
|
127
127
|
elif op_id.endswith("_retrieve"):
|
128
128
|
resource = op_id.removesuffix("_retrieve")
|
129
|
-
#
|
130
|
-
return f"get{self._to_pascal_case(resource)
|
129
|
+
# Add ById suffix to distinguish from list
|
130
|
+
return f"get{self._to_pascal_case(resource)}ById"
|
131
131
|
elif op_id.endswith("_create"):
|
132
132
|
resource = op_id.removesuffix("_create")
|
133
133
|
return f"create{self._to_pascal_case(resource)}"
|
@@ -180,24 +180,23 @@ class HooksGenerator:
|
|
180
180
|
Convert operation to hook name.
|
181
181
|
|
182
182
|
Examples:
|
183
|
-
users_list (GET) ->
|
184
|
-
users_retrieve (GET) ->
|
185
|
-
users_create (POST) ->
|
186
|
-
users_update (PUT) ->
|
187
|
-
users_partial_update (PATCH) ->
|
188
|
-
users_destroy (DELETE) ->
|
183
|
+
users_list (GET) -> useUsersList
|
184
|
+
users_retrieve (GET) -> useUsersById
|
185
|
+
users_create (POST) -> useCreateUsers
|
186
|
+
users_update (PUT) -> useUpdateUsers
|
187
|
+
users_partial_update (PATCH) -> usePartialUpdateUsers
|
188
|
+
users_destroy (DELETE) -> useDeleteUsers
|
189
189
|
"""
|
190
190
|
op_id = operation.operation_id
|
191
191
|
|
192
|
+
# Keep full resource name and add suffixes for uniqueness
|
192
193
|
if op_id.endswith("_list"):
|
193
|
-
resource = op_id.
|
194
|
-
|
195
|
-
return f"use{self._to_pascal_case(resource)}"
|
194
|
+
resource = op_id.removesuffix("_list")
|
195
|
+
return f"use{self._to_pascal_case(resource)}List"
|
196
196
|
elif op_id.endswith("_retrieve"):
|
197
|
-
resource = op_id.
|
198
|
-
#
|
199
|
-
|
200
|
-
return f"use{self._to_pascal_case(resource_singular)}"
|
197
|
+
resource = op_id.removesuffix("_retrieve")
|
198
|
+
# Add ById suffix to distinguish from list
|
199
|
+
return f"use{self._to_pascal_case(resource)}ById"
|
201
200
|
elif op_id.endswith("_create"):
|
202
201
|
resource = op_id.removesuffix("_create")
|
203
202
|
return f"useCreate{self._to_pascal_case(resource)}"
|
@@ -215,18 +214,17 @@ class HooksGenerator:
|
|
215
214
|
return f"use{self._to_pascal_case(op_id)}"
|
216
215
|
|
217
216
|
def _operation_to_fetcher_name(self, operation: IROperationObject) -> str:
|
218
|
-
"""Get corresponding fetcher function name."""
|
217
|
+
"""Get corresponding fetcher function name (must match fetchers_generator logic)."""
|
219
218
|
op_id = operation.operation_id
|
220
219
|
|
221
|
-
#
|
220
|
+
# Must match fetchers_generator._operation_to_function_name() exactly
|
222
221
|
if op_id.endswith("_list"):
|
223
222
|
resource = op_id.removesuffix("_list")
|
224
|
-
return f"get{self._to_pascal_case(resource)}"
|
223
|
+
return f"get{self._to_pascal_case(resource)}List"
|
225
224
|
elif op_id.endswith("_retrieve"):
|
226
225
|
resource = op_id.removesuffix("_retrieve")
|
227
|
-
#
|
228
|
-
|
229
|
-
return f"get{self._to_pascal_case(resource_singular)}"
|
226
|
+
# Add ById suffix to match fetchers_generator
|
227
|
+
return f"get{self._to_pascal_case(resource)}ById"
|
230
228
|
elif op_id.endswith("_create"):
|
231
229
|
resource = op_id.removesuffix("_create")
|
232
230
|
return f"create{self._to_pascal_case(resource)}"
|
@@ -240,7 +238,7 @@ class HooksGenerator:
|
|
240
238
|
resource = op_id.removesuffix("_destroy")
|
241
239
|
return f"delete{self._to_pascal_case(resource)}"
|
242
240
|
else:
|
243
|
-
return
|
241
|
+
return self._to_camel_case(op_id)
|
244
242
|
|
245
243
|
def _get_param_info(self, operation: IROperationObject) -> dict:
|
246
244
|
"""
|
@@ -391,6 +389,11 @@ class HooksGenerator:
|
|
391
389
|
"""Convert snake_case to PascalCase."""
|
392
390
|
return ''.join(word.capitalize() for word in snake_str.split('_'))
|
393
391
|
|
392
|
+
def _to_camel_case(self, snake_str: str) -> str:
|
393
|
+
"""Convert snake_case to camelCase."""
|
394
|
+
components = snake_str.split('_')
|
395
|
+
return components[0] + ''.join(x.capitalize() for x in components[1:])
|
396
|
+
|
394
397
|
def generate_tag_hooks_file(
|
395
398
|
self,
|
396
399
|
tag: str,
|
@@ -140,35 +140,39 @@ class ModelsGenerator:
|
|
140
140
|
Examples:
|
141
141
|
id: number;
|
142
142
|
username: string;
|
143
|
-
email?: string
|
143
|
+
email?: string;
|
144
144
|
status: Enums.StatusEnum;
|
145
145
|
"""
|
146
146
|
# Check if this field is an enum
|
147
147
|
if schema.enum and schema.name:
|
148
148
|
# Use enum type from shared enums (sanitized)
|
149
149
|
ts_type = f"Enums.{self.base.sanitize_enum_name(schema.name)}"
|
150
|
-
|
151
|
-
ts_type = f"{ts_type} | null"
|
150
|
+
# Don't add | null for nullable - use optional marker instead
|
152
151
|
# Check if this field is a reference to an enum (via $ref)
|
153
152
|
elif schema.ref and schema.ref in self.context.schemas:
|
154
153
|
ref_schema = self.context.schemas[schema.ref]
|
155
154
|
if ref_schema.enum:
|
156
155
|
# This is a reference to an enum component (sanitized to PascalCase)
|
157
156
|
ts_type = f"Enums.{self.base.sanitize_enum_name(schema.ref)}"
|
158
|
-
|
159
|
-
ts_type = f"{ts_type} | null"
|
157
|
+
# Don't add | null for nullable - use optional marker instead
|
160
158
|
else:
|
161
|
-
# Regular reference
|
159
|
+
# Regular reference - get base type without | null
|
162
160
|
ts_type = schema.typescript_type
|
161
|
+
# Remove | null suffix if present (we'll use optional marker instead)
|
162
|
+
if ts_type.endswith(" | null"):
|
163
|
+
ts_type = ts_type[:-7] # Remove " | null"
|
163
164
|
else:
|
164
|
-
# Get TypeScript type
|
165
|
+
# Get TypeScript type and remove | null suffix if present
|
165
166
|
ts_type = schema.typescript_type
|
167
|
+
if ts_type.endswith(" | null"):
|
168
|
+
ts_type = ts_type[:-7] # Remove " | null"
|
166
169
|
|
167
170
|
# Check if required
|
168
171
|
is_required = name in required_fields
|
169
172
|
|
170
|
-
# Optional marker
|
171
|
-
|
173
|
+
# Optional marker - use for both non-required AND nullable fields
|
174
|
+
# This converts Django's nullable=True to TypeScript's optional (undefined)
|
175
|
+
optional_marker = "" if is_required and not schema.nullable else "?"
|
172
176
|
|
173
177
|
# Comment
|
174
178
|
if schema.description:
|
@@ -117,14 +117,11 @@ class SchemasGenerator:
|
|
117
117
|
# Check if required
|
118
118
|
is_required = name in required_fields
|
119
119
|
|
120
|
-
# Handle optional fields
|
121
|
-
|
120
|
+
# Handle optional fields - use .optional() for both non-required AND nullable
|
121
|
+
# This converts Django's nullable=True to TypeScript's optional (undefined)
|
122
|
+
if not is_required or schema.nullable:
|
122
123
|
zod_type = f"{zod_type}.optional()"
|
123
124
|
|
124
|
-
# Handle nullable fields
|
125
|
-
if schema.nullable:
|
126
|
-
zod_type = f"{zod_type}.nullable()"
|
127
|
-
|
128
125
|
return f"{name}: {zod_type}"
|
129
126
|
|
130
127
|
def _map_type_to_zod(self, schema: IRSchemaObject) -> str:
|
@@ -79,7 +79,7 @@ class DashboardManager(BaseCfgModule):
|
|
79
79
|
if self.should_enable_tasks():
|
80
80
|
operations_items.extend([
|
81
81
|
NavigationItem(title="Background Tasks", icon=Icons.TASK, link="/admin/django_dramatiq/task/"),
|
82
|
-
NavigationItem(title="Task Dashboard", icon=Icons.SETTINGS_APPLICATIONS, link="/cfg/
|
82
|
+
NavigationItem(title="Task Dashboard", icon=Icons.SETTINGS_APPLICATIONS, link="/cfg/tasks/admin/dashboard/"),
|
83
83
|
])
|
84
84
|
|
85
85
|
# Maintenance Mode (if enabled)
|
@@ -194,7 +194,7 @@ class DashboardManager(BaseCfgModule):
|
|
194
194
|
|
195
195
|
# Main dashboard (always show if payments app enabled)
|
196
196
|
payments_items.append(
|
197
|
-
NavigationItem(title="Payment Dashboard", icon=Icons.DASHBOARD, link="/cfg/
|
197
|
+
NavigationItem(title="Payment Dashboard", icon=Icons.DASHBOARD, link="/cfg/payments/admin/")
|
198
198
|
)
|
199
199
|
|
200
200
|
# Always show basic admin models (even if payments functionality is disabled)
|
@@ -208,13 +208,13 @@ class DashboardManager(BaseCfgModule):
|
|
208
208
|
# Add advanced features only if payments functionality is enabled
|
209
209
|
if config.enabled:
|
210
210
|
# payments_items.append(
|
211
|
-
# NavigationItem(title="Webhook Dashboard", icon=Icons.WEBHOOK, link="/cfg/
|
211
|
+
# NavigationItem(title="Webhook Dashboard", icon=Icons.WEBHOOK, link="/cfg/payments/admin/webhooks/")
|
212
212
|
# )
|
213
213
|
# payments_items.append(
|
214
|
-
# NavigationItem(title="Create Payment", icon=Icons.ADD, link="/cfg/
|
214
|
+
# NavigationItem(title="Create Payment", icon=Icons.ADD, link="/cfg/payments/admin/payments/create/")
|
215
215
|
# )
|
216
216
|
# payments_items.append(
|
217
|
-
# NavigationItem(title="Currency Converter", icon=Icons.CURRENCY_EXCHANGE, link="/cfg/
|
217
|
+
# NavigationItem(title="Currency Converter", icon=Icons.CURRENCY_EXCHANGE, link="/cfg/payments/admin/tools/converter/")
|
218
218
|
# )
|
219
219
|
|
220
220
|
# Show subscription features only if enabled
|
@@ -246,7 +246,7 @@ class DashboardManager(BaseCfgModule):
|
|
246
246
|
except Exception:
|
247
247
|
# Fallback
|
248
248
|
payments_items = [
|
249
|
-
NavigationItem(title="Payment Dashboard", icon=Icons.DASHBOARD, link="/cfg/
|
249
|
+
NavigationItem(title="Payment Dashboard", icon=Icons.DASHBOARD, link="/cfg/payments/admin/"),
|
250
250
|
NavigationItem(title="Universal Payments", icon=Icons.ACCOUNT_BALANCE, link="/admin/payments/universalpayment/"),
|
251
251
|
]
|
252
252
|
|
django_cfg/pyproject.toml
CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "django-cfg"
|
7
|
-
version = "1.4.
|
7
|
+
version = "1.4.15"
|
8
8
|
description = "Django AI framework with built-in agents, type-safe Pydantic v2 configuration, and 8 enterprise apps. Replace settings.py, validate at startup, 90% less code. Production-ready AI workflows for Django."
|
9
9
|
readme = "README.md"
|
10
10
|
keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "ai-agents", "enterprise-django", "django-settings", "type-safe-config",]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: django-cfg
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.15
|
4
4
|
Summary: Django AI framework with built-in agents, type-safe Pydantic v2 configuration, and 8 enterprise apps. Replace settings.py, validate at startup, 90% less code. Production-ready AI workflows for Django.
|
5
5
|
Project-URL: Homepage, https://djangocfg.com
|
6
6
|
Project-URL: Documentation, https://djangocfg.com
|