django-cfg 1.4.104__py3-none-any.whl → 1.4.105__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +1 -1
- django_cfg/pyproject.toml +1 -1
- django_cfg/templates/admin/DUAL_TAB_ARCHITECTURE.md +57 -0
- django_cfg/templates/admin/index.html +60 -7
- {django_cfg-1.4.104.dist-info → django_cfg-1.4.105.dist-info}/METADATA +1 -1
- {django_cfg-1.4.104.dist-info → django_cfg-1.4.105.dist-info}/RECORD +9 -9
- {django_cfg-1.4.104.dist-info → django_cfg-1.4.105.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.104.dist-info → django_cfg-1.4.105.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.104.dist-info → django_cfg-1.4.105.dist-info}/licenses/LICENSE +0 -0
django_cfg/__init__.py
CHANGED
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.105"
|
|
8
8
|
description = "Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "nextjs-admin", "react-admin", "websocket", "centrifugo", "real-time", "typescript-generation", "ai-agents", "enterprise-django", "django-settings", "type-safe-config", "modern-django",]
|
|
@@ -180,6 +180,63 @@ resetIframe(tab) {
|
|
|
180
180
|
**Why Reset?**
|
|
181
181
|
This ensures that when users switch back to a tab, it starts from the home page rather than whatever route they navigated to previously.
|
|
182
182
|
|
|
183
|
+
### Open in New Window
|
|
184
|
+
|
|
185
|
+
The External Admin tab (Tab 2) includes an "Open in New Window" button that allows users to break out of the iframe and work in a dedicated browser window/tab:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
openInNewWindow() {
|
|
189
|
+
// Get the current iframe URL for the External Admin tab
|
|
190
|
+
const iframe = document.getElementById('nextjs-dashboard-iframe-nextjs');
|
|
191
|
+
if (iframe) {
|
|
192
|
+
const currentUrl = iframe.src || iframe.getAttribute('data-original-src');
|
|
193
|
+
if (currentUrl) {
|
|
194
|
+
window.open(currentUrl, '_blank', 'noopener,noreferrer');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Features:**
|
|
201
|
+
- Only visible when External Admin tab is active (`x-show="activeTab === 'nextjs'"`)
|
|
202
|
+
- Opens current iframe URL in new window with `noopener,noreferrer` security flags
|
|
203
|
+
- Preserves current route via `postMessage` tracking (see below)
|
|
204
|
+
- Styled as action button with icon and text label
|
|
205
|
+
|
|
206
|
+
**How Route Tracking Works:**
|
|
207
|
+
|
|
208
|
+
In **production** (same-origin), `iframe.src` updates automatically:
|
|
209
|
+
```javascript
|
|
210
|
+
// iframe.src reflects current URL automatically
|
|
211
|
+
window.open(iframe.src, '_blank');
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
In **development** (cross-origin), we track navigation via `postMessage`:
|
|
215
|
+
```javascript
|
|
216
|
+
// iframe sends navigation events
|
|
217
|
+
case 'iframe-navigation':
|
|
218
|
+
if (data?.path) {
|
|
219
|
+
alpineData.currentNextjsPath = data.path; // Track path
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Button uses tracked path
|
|
223
|
+
openInNewWindow() {
|
|
224
|
+
const url = new URL(baseUrl);
|
|
225
|
+
url.pathname = this.currentNextjsPath; // Apply tracked path
|
|
226
|
+
window.open(url.toString(), '_blank');
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Why postMessage?**
|
|
231
|
+
Cross-origin iframes cannot access `iframe.src` due to browser security (CORS). The iframe must explicitly send navigation events via `postMessage`.
|
|
232
|
+
|
|
233
|
+
**Why This is Useful:**
|
|
234
|
+
- Full browser features (address bar, bookmarks, etc.)
|
|
235
|
+
- No iframe sandbox restrictions
|
|
236
|
+
- Easier debugging (browser DevTools)
|
|
237
|
+
- Better for complex workflows that require multiple windows
|
|
238
|
+
- Copy/paste and other browser features work better
|
|
239
|
+
|
|
183
240
|
## Static File Serving
|
|
184
241
|
|
|
185
242
|
### Built-in Admin (Tab 1)
|
|
@@ -136,6 +136,7 @@
|
|
|
136
136
|
<div x-data="{
|
|
137
137
|
activeTab: 'builtin',
|
|
138
138
|
previousTab: 'builtin',
|
|
139
|
+
currentNextjsPath: '',
|
|
139
140
|
switchTab(tab) {
|
|
140
141
|
if (this.previousTab !== tab) {
|
|
141
142
|
// Reset iframe to initial URL when switching tabs
|
|
@@ -152,6 +153,34 @@
|
|
|
152
153
|
const originalSrc = iframe.getAttribute('data-original-src') || iframe.src;
|
|
153
154
|
iframe.src = originalSrc;
|
|
154
155
|
}
|
|
156
|
+
// Reset path when resetting iframe
|
|
157
|
+
if (tab === 'nextjs') {
|
|
158
|
+
this.currentNextjsPath = '';
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
openInNewWindow() {
|
|
162
|
+
// Get the current iframe URL for the External Admin tab
|
|
163
|
+
const iframe = document.getElementById('nextjs-dashboard-iframe-nextjs');
|
|
164
|
+
if (!iframe) return;
|
|
165
|
+
|
|
166
|
+
// Get base URL from iframe src or data-original-src
|
|
167
|
+
let baseUrl = iframe.src || iframe.getAttribute('data-original-src');
|
|
168
|
+
|
|
169
|
+
// If we have a tracked path from postMessage, use it
|
|
170
|
+
if (this.currentNextjsPath) {
|
|
171
|
+
try {
|
|
172
|
+
const url = new URL(baseUrl);
|
|
173
|
+
// Replace pathname with tracked path
|
|
174
|
+
url.pathname = this.currentNextjsPath;
|
|
175
|
+
baseUrl = url.toString();
|
|
176
|
+
} catch (e) {
|
|
177
|
+
console.warn('[Django-CFG] Failed to construct URL with path:', e);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (baseUrl) {
|
|
182
|
+
window.open(baseUrl, '_blank', 'noopener,noreferrer');
|
|
183
|
+
}
|
|
155
184
|
}
|
|
156
185
|
}">
|
|
157
186
|
{% if is_frontend_dev_mode %}
|
|
@@ -200,12 +229,25 @@
|
|
|
200
229
|
</button>
|
|
201
230
|
</nav>
|
|
202
231
|
|
|
203
|
-
<!-- Version info -->
|
|
204
|
-
<div class="
|
|
205
|
-
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
232
|
+
<!-- Actions & Version info -->
|
|
233
|
+
<div class="flex items-center gap-4 py-4">
|
|
234
|
+
<!-- Open in new window button (only for External Admin tab) -->
|
|
235
|
+
<button @click="openInNewWindow()"
|
|
236
|
+
x-show="activeTab === 'nextjs'"
|
|
237
|
+
title="Open in new window"
|
|
238
|
+
class="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md text-gray-600 hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-gray-100 dark:hover:bg-gray-700 transition-all duration-150"
|
|
239
|
+
style="display: none;">
|
|
240
|
+
<span class="material-icons" style="font-size: 16px;">open_in_new</span>
|
|
241
|
+
<span>Open in New Window</span>
|
|
242
|
+
</button>
|
|
243
|
+
|
|
244
|
+
<!-- Version info -->
|
|
245
|
+
<div class="text-xs text-gray-400 dark:text-gray-500">
|
|
246
|
+
{% load django_cfg %}
|
|
247
|
+
<a href="{% lib_site_url %}" class="text-blue-600 hover:text-blue-700">
|
|
248
|
+
{% lib_name %}
|
|
249
|
+
</a>
|
|
250
|
+
</div>
|
|
209
251
|
</div>
|
|
210
252
|
</div>
|
|
211
253
|
</div>
|
|
@@ -419,7 +461,18 @@
|
|
|
419
461
|
break;
|
|
420
462
|
|
|
421
463
|
case 'iframe-navigation':
|
|
422
|
-
|
|
464
|
+
console.log('[Django-CFG] iframe navigated to:', data?.path);
|
|
465
|
+
// Track current path for "Open in New Window" button
|
|
466
|
+
if (iframe.id === 'nextjs-dashboard-iframe-nextjs' && data?.path) {
|
|
467
|
+
// Update Alpine.js data
|
|
468
|
+
const alpineEl = document.querySelector('[x-data]');
|
|
469
|
+
if (alpineEl && window.Alpine) {
|
|
470
|
+
const alpineData = window.Alpine.$data(alpineEl);
|
|
471
|
+
if (alpineData) {
|
|
472
|
+
alpineData.currentNextjsPath = data.path;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
423
476
|
break;
|
|
424
477
|
|
|
425
478
|
default:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-cfg
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.105
|
|
4
4
|
Summary: Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features.
|
|
5
5
|
Project-URL: Homepage, https://djangocfg.com
|
|
6
6
|
Project-URL: Documentation, https://djangocfg.com
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
django_cfg/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
django_cfg/__init__.py,sha256=
|
|
2
|
+
django_cfg/__init__.py,sha256=MXUS0jQw0iZtqEX_dQus7hIBxuCa6q1o31FhWBRFJOo,1621
|
|
3
3
|
django_cfg/apps.py,sha256=72m3uuvyqGiLx6gOfE-BD3P61jddCCERuBOYpxTX518,1605
|
|
4
4
|
django_cfg/config.py,sha256=y4Z3rnYsHBE0TehpwAIPaxr---mkvyKrZGGsNwYso74,1398
|
|
5
5
|
django_cfg/apps/__init__.py,sha256=JtDmEYt1OcleWM2ZaeX0LKDnRQzPOavfaXBWG4ECB5Q,26
|
|
@@ -1074,8 +1074,8 @@ django_cfg/static/js/api/support/index.mjs,sha256=oPA3iGkUWYyKQuJlI5-tSxD3AOhwlA
|
|
|
1074
1074
|
django_cfg/static/js/api/tasks/client.mjs,sha256=tIy8K-finXzTUL9kOo_L4Q1kchDaHyuzjwS4VymiWPM,3579
|
|
1075
1075
|
django_cfg/static/js/api/tasks/index.mjs,sha256=yCY1GzdD-RtFZ3pAfk1l0msgO1epyo0lsGCjH0g1Afc,294
|
|
1076
1076
|
django_cfg/templates/__init__.py,sha256=IzLjt-a7VIJ0OutmAE1_-w0_LpL2u0MgGpnIabjZuW8,19
|
|
1077
|
-
django_cfg/templates/admin/DUAL_TAB_ARCHITECTURE.md,sha256=
|
|
1078
|
-
django_cfg/templates/admin/index.html,sha256=
|
|
1077
|
+
django_cfg/templates/admin/DUAL_TAB_ARCHITECTURE.md,sha256=CL8E3K4rFpXeQiNgrYSMvCW1y-eFaoXxxsI58zPf9dY,17562
|
|
1078
|
+
django_cfg/templates/admin/index.html,sha256=T8atxHnk7f6hiRDA4SKhpRY76srDB-auLANmjSSbejs,20654
|
|
1079
1079
|
django_cfg/templates/emails/base_email.html,sha256=TWcvYa2IHShlF_E8jf1bWZStRO0v8G4L_GexPxvz6XQ,8836
|
|
1080
1080
|
django_cfg/templates/unfold/layouts/skeleton.html,sha256=2ArkcNZ34mFs30cOAsTQ1EZiDXcB0aVxkO71lJq9SLE,718
|
|
1081
1081
|
django_cfg/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -1087,9 +1087,9 @@ django_cfg/utils/version_check.py,sha256=WO51J2m2e-wVqWCRwbultEwu3q1lQasV67Mw2aa
|
|
|
1087
1087
|
django_cfg/CHANGELOG.md,sha256=jtT3EprqEJkqSUh7IraP73vQ8PmKUMdRtznQsEnqDZk,2052
|
|
1088
1088
|
django_cfg/CONTRIBUTING.md,sha256=DU2kyQ6PU0Z24ob7O_OqKWEYHcZmJDgzw-lQCmu6uBg,3041
|
|
1089
1089
|
django_cfg/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
|
|
1090
|
-
django_cfg/pyproject.toml,sha256=
|
|
1091
|
-
django_cfg-1.4.
|
|
1092
|
-
django_cfg-1.4.
|
|
1093
|
-
django_cfg-1.4.
|
|
1094
|
-
django_cfg-1.4.
|
|
1095
|
-
django_cfg-1.4.
|
|
1090
|
+
django_cfg/pyproject.toml,sha256=mSzm-YWCFBLu53-OiCS9-wjIBxA9vm-yMg6Dii7FzYc,8573
|
|
1091
|
+
django_cfg-1.4.105.dist-info/METADATA,sha256=mQjCmuDpR7D-vMY12IAIzJskSnrlBEBNWQ2Fwn-vAEc,23734
|
|
1092
|
+
django_cfg-1.4.105.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
1093
|
+
django_cfg-1.4.105.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
|
|
1094
|
+
django_cfg-1.4.105.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
|
|
1095
|
+
django_cfg-1.4.105.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|