django-admin-react 1.0.4__tar.gz → 1.2.0__tar.gz
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_admin_react-1.0.4 → django_admin_react-1.2.0}/PKG-INFO +54 -1
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/README.md +53 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/conf.py +32 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/static/admin_react/.vite/manifest.json +3 -3
- django_admin_react-1.0.4/django_admin_react/static/admin_react/assets/JsonViewer-BmNjjThH.js → django_admin_react-1.2.0/django_admin_react/static/admin_react/assets/JsonViewer-LPoiv-e5.js +1 -1
- django_admin_react-1.0.4/django_admin_react/static/admin_react/assets/index-qL4Bgx80.js → django_admin_react-1.2.0/django_admin_react/static/admin_react/assets/index-BkdeALer.js +4 -4
- django_admin_react-1.2.0/django_admin_react/static/admin_react/assets/index-DMT_bXJw.css +1 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/static/admin_react/index.html +2 -2
- django_admin_react-1.2.0/django_admin_react/templates/admin/base_site.html +37 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/templates/admin_react/index.html +8 -0
- django_admin_react-1.2.0/django_admin_react/templates/django_admin_react/_experience_toggle_strip.html +22 -0
- django_admin_react-1.2.0/django_admin_react/templatetags/__init__.py +0 -0
- django_admin_react-1.2.0/django_admin_react/templatetags/experience_toggle.py +82 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/views.py +32 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/pyproject.toml +1 -1
- django_admin_react-1.0.4/django_admin_react/static/admin_react/assets/index-C4IuiLep.css +0 -1
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/LICENSE +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/README.md +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/__init__.py +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/apps.py +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/audit.py +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/pwa.py +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/templates/README.md +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/templates/admin_react/README.md +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/templates/admin_react/login.html +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/templates/admin_react/sw.js +0 -0
- {django_admin_react-1.0.4 → django_admin_react-1.2.0}/django_admin_react/urls.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: django-admin-react
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: A drop-in React single-page admin for Django, driven entirely by ModelAdmin.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: django,admin,react,spa,tailwind
|
|
@@ -298,6 +298,59 @@ urlpatterns = [
|
|
|
298
298
|
]
|
|
299
299
|
```
|
|
300
300
|
|
|
301
|
+
#### Experience-toggle strip (optional)
|
|
302
|
+
|
|
303
|
+
During the rollout, show a thin **persistent** strip at the top of
|
|
304
|
+
every page on **both** admins that links to the same page on the
|
|
305
|
+
other admin. Users can switch surfaces in one click, regardless of
|
|
306
|
+
which one they're on:
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
# settings.py
|
|
310
|
+
DJANGO_ADMIN_REACT = {
|
|
311
|
+
"LEGACY_ADMIN_URL_PREFIX": "admin/", # the legacy admin's mount
|
|
312
|
+
"REACT_ADMIN_URL_PREFIX": "admin2/", # this package's mount
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Both values must match the prefixes you used in `urls.py`. When set:
|
|
317
|
+
|
|
318
|
+
- The **React SPA** renders a strip linking the same path under the
|
|
319
|
+
legacy admin's mount (with `?query=string` preserved and a trailing
|
|
320
|
+
slash, since Django admin URLs require one).
|
|
321
|
+
- The **legacy Django admin** renders the mirror strip linking the
|
|
322
|
+
matching React URL.
|
|
323
|
+
|
|
324
|
+
Set `LEGACY_ADMIN_URL_PREFIX` alone if you only want the SPA → legacy
|
|
325
|
+
direction (reverse direction stays off).
|
|
326
|
+
|
|
327
|
+
##### `INSTALLED_APPS` ordering
|
|
328
|
+
|
|
329
|
+
For the legacy-side strip, list `django_admin_react` **before**
|
|
330
|
+
`django.contrib.admin`. Django's template loader resolves
|
|
331
|
+
`admin/base_site.html` left-to-right and the first match wins —
|
|
332
|
+
the package's override of that template injects the strip:
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
INSTALLED_APPS = [
|
|
336
|
+
"django_admin_react", # ← BEFORE django.contrib.admin
|
|
337
|
+
"django.contrib.admin",
|
|
338
|
+
# ...
|
|
339
|
+
]
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
If you don't enable the legacy-side strip (`REACT_ADMIN_URL_PREFIX`
|
|
343
|
+
unset) the ordering doesn't matter — the override is a no-op for
|
|
344
|
+
consumers who haven't opted in.
|
|
345
|
+
|
|
346
|
+
##### UX contract
|
|
347
|
+
|
|
348
|
+
The strip is **subtle and persistent**: one line tall, neutral
|
|
349
|
+
chrome, no dismiss control. Operators turn it on/off via the
|
|
350
|
+
settings; end-users do not. When you remove the settings (or set
|
|
351
|
+
them to `None`), the strips disappear on the next page load —
|
|
352
|
+
completing the migration.
|
|
353
|
+
|
|
301
354
|
---
|
|
302
355
|
|
|
303
356
|
## Extend without writing React
|
|
@@ -265,6 +265,59 @@ urlpatterns = [
|
|
|
265
265
|
]
|
|
266
266
|
```
|
|
267
267
|
|
|
268
|
+
#### Experience-toggle strip (optional)
|
|
269
|
+
|
|
270
|
+
During the rollout, show a thin **persistent** strip at the top of
|
|
271
|
+
every page on **both** admins that links to the same page on the
|
|
272
|
+
other admin. Users can switch surfaces in one click, regardless of
|
|
273
|
+
which one they're on:
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
# settings.py
|
|
277
|
+
DJANGO_ADMIN_REACT = {
|
|
278
|
+
"LEGACY_ADMIN_URL_PREFIX": "admin/", # the legacy admin's mount
|
|
279
|
+
"REACT_ADMIN_URL_PREFIX": "admin2/", # this package's mount
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Both values must match the prefixes you used in `urls.py`. When set:
|
|
284
|
+
|
|
285
|
+
- The **React SPA** renders a strip linking the same path under the
|
|
286
|
+
legacy admin's mount (with `?query=string` preserved and a trailing
|
|
287
|
+
slash, since Django admin URLs require one).
|
|
288
|
+
- The **legacy Django admin** renders the mirror strip linking the
|
|
289
|
+
matching React URL.
|
|
290
|
+
|
|
291
|
+
Set `LEGACY_ADMIN_URL_PREFIX` alone if you only want the SPA → legacy
|
|
292
|
+
direction (reverse direction stays off).
|
|
293
|
+
|
|
294
|
+
##### `INSTALLED_APPS` ordering
|
|
295
|
+
|
|
296
|
+
For the legacy-side strip, list `django_admin_react` **before**
|
|
297
|
+
`django.contrib.admin`. Django's template loader resolves
|
|
298
|
+
`admin/base_site.html` left-to-right and the first match wins —
|
|
299
|
+
the package's override of that template injects the strip:
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
INSTALLED_APPS = [
|
|
303
|
+
"django_admin_react", # ← BEFORE django.contrib.admin
|
|
304
|
+
"django.contrib.admin",
|
|
305
|
+
# ...
|
|
306
|
+
]
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
If you don't enable the legacy-side strip (`REACT_ADMIN_URL_PREFIX`
|
|
310
|
+
unset) the ordering doesn't matter — the override is a no-op for
|
|
311
|
+
consumers who haven't opted in.
|
|
312
|
+
|
|
313
|
+
##### UX contract
|
|
314
|
+
|
|
315
|
+
The strip is **subtle and persistent**: one line tall, neutral
|
|
316
|
+
chrome, no dismiss control. Operators turn it on/off via the
|
|
317
|
+
settings; end-users do not. When you remove the settings (or set
|
|
318
|
+
them to `None`), the strips disappear on the next page load —
|
|
319
|
+
completing the migration.
|
|
320
|
+
|
|
268
321
|
---
|
|
269
322
|
|
|
270
323
|
## Extend without writing React
|
|
@@ -99,6 +99,36 @@ DEFAULTS: dict[str, Any] = {
|
|
|
99
99
|
# `django_admin_react.urls` skips the inline `api/v1/` include so
|
|
100
100
|
# there is no double-mount.
|
|
101
101
|
"API_URL_PREFIX": None,
|
|
102
|
+
# ``LEGACY_ADMIN_URL_PREFIX`` — opt-in escape-hatch banner (#577).
|
|
103
|
+
# When set, every SPA page renders a thin notice banner at the top
|
|
104
|
+
# linking to **the same page** under the legacy Django admin's URL
|
|
105
|
+
# prefix. Useful during a progressive migration: end-users with
|
|
106
|
+
# muscle memory for ``/admin/`` (or wherever the legacy admin is
|
|
107
|
+
# mounted) can return to the classic surface in one click, and the
|
|
108
|
+
# bug list grows from "what they clicked back for." Default
|
|
109
|
+
# ``None`` keeps behaviour unchanged — no banner, no extra
|
|
110
|
+
# requests, no SPA overhead.
|
|
111
|
+
#
|
|
112
|
+
# The value matches the prefix the consumer registered the legacy
|
|
113
|
+
# admin under in ``urls.py`` — e.g. ``"admin/"`` for
|
|
114
|
+
# ``urlpatterns = [path("admin/", legacy_admin.urls), ...]``. The
|
|
115
|
+
# SPA computes the matching legacy URL by swapping its own mount
|
|
116
|
+
# for this value (both admins use the same ``app_label/model_name``
|
|
117
|
+
# URL shape, so it's a straight prefix swap with no per-route
|
|
118
|
+
# mapping). When the matching legacy route doesn't exist, the
|
|
119
|
+
# legacy admin 404s — same outcome as visiting that URL directly.
|
|
120
|
+
"LEGACY_ADMIN_URL_PREFIX": None,
|
|
121
|
+
# ``REACT_ADMIN_URL_PREFIX`` — sibling of ``LEGACY_ADMIN_URL_PREFIX``
|
|
122
|
+
# (#584). When **both** are set, the legacy Django admin renders a
|
|
123
|
+
# mirror strip at the top of every page linking the same path under
|
|
124
|
+
# the React admin's mount — so a user on either surface can swap
|
|
125
|
+
# to the other in one click. The value is the prefix the SPA was
|
|
126
|
+
# mounted at in ``urls.py`` — e.g. ``"admin2/"`` for
|
|
127
|
+
# ``urlpatterns = [path("admin2/", include("django_admin_react.urls")), ...]``.
|
|
128
|
+
# When only ``LEGACY_ADMIN_URL_PREFIX`` is set, only the SPA-side
|
|
129
|
+
# strip renders (reverse direction stays off — no implicit guess
|
|
130
|
+
# at the consumer's chosen mount).
|
|
131
|
+
"REACT_ADMIN_URL_PREFIX": None,
|
|
102
132
|
"PWA_NAME": None,
|
|
103
133
|
"PWA_SHORT_NAME": None,
|
|
104
134
|
"PWA_ICONS": None,
|
|
@@ -122,6 +152,8 @@ class _PackageSettings:
|
|
|
122
152
|
PRIMARY_COLOR: str = DEFAULTS["PRIMARY_COLOR"]
|
|
123
153
|
REACT_LOGIN: bool = DEFAULTS["REACT_LOGIN"]
|
|
124
154
|
API_URL_PREFIX: str | None = DEFAULTS["API_URL_PREFIX"]
|
|
155
|
+
LEGACY_ADMIN_URL_PREFIX: str | None = DEFAULTS["LEGACY_ADMIN_URL_PREFIX"]
|
|
156
|
+
REACT_ADMIN_URL_PREFIX: str | None = DEFAULTS["REACT_ADMIN_URL_PREFIX"]
|
|
125
157
|
PWA_NAME: str | None = DEFAULTS["PWA_NAME"]
|
|
126
158
|
PWA_SHORT_NAME: str | None = DEFAULTS["PWA_SHORT_NAME"]
|
|
127
159
|
PWA_ICONS: list[dict[str, str]] | None = DEFAULTS["PWA_ICONS"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"../../packages/details/src/JsonViewer.tsx": {
|
|
3
|
-
"file": "assets/JsonViewer-
|
|
3
|
+
"file": "assets/JsonViewer-LPoiv-e5.js",
|
|
4
4
|
"name": "JsonViewer",
|
|
5
5
|
"src": "../../packages/details/src/JsonViewer.tsx",
|
|
6
6
|
"isDynamicEntry": true,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
]
|
|
10
10
|
},
|
|
11
11
|
"index.html": {
|
|
12
|
-
"file": "assets/index-
|
|
12
|
+
"file": "assets/index-BkdeALer.js",
|
|
13
13
|
"name": "index",
|
|
14
14
|
"src": "index.html",
|
|
15
15
|
"isEntry": true,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"../../packages/details/src/JsonViewer.tsx"
|
|
18
18
|
],
|
|
19
19
|
"css": [
|
|
20
|
-
"assets/index-
|
|
20
|
+
"assets/index-DMT_bXJw.css"
|
|
21
21
|
]
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as x,r as l,j as e,C as h}from"./index-
|
|
1
|
+
import{c as x,r as l,j as e,C as h}from"./index-BkdeALer.js";const p=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],g=x("chevron-right",p);const y=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],j=x("copy",y);function N({raw:r,parsed:t}){const[s,c]=l.useState(!1);async function a(){try{await navigator.clipboard.writeText(r),c(!0),setTimeout(()=>c(!1),2e3)}catch{}}return e.jsxs("div",{className:"relative w-full overflow-x-auto rounded border border-gray-200 bg-gray-50 p-3 font-mono text-xs leading-relaxed text-gray-800 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200",children:[e.jsx("button",{type:"button",onClick:a,"aria-label":"Copy JSON",title:s?"Copied":"Copy",className:"absolute right-2 top-2 inline-flex h-6 w-6 items-center justify-center rounded border border-gray-300 bg-white text-gray-600 hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700",children:s?e.jsx(h,{className:"h-3.5 w-3.5 text-green-600","aria-hidden":!0}):e.jsx(j,{className:"h-3.5 w-3.5","aria-hidden":!0})}),e.jsx(o,{value:t,depth:0})]})}function o({value:r,depth:t}){return r===null?e.jsx("span",{className:"text-purple-600 dark:text-purple-400",children:"null"}):typeof r=="boolean"?e.jsx("span",{className:"text-purple-600 dark:text-purple-400",children:r?"true":"false"}):typeof r=="number"?e.jsx("span",{className:"text-blue-700",children:String(r)}):typeof r=="string"?e.jsxs("span",{className:"text-green-700 dark:text-green-400",children:['"',r,'"']}):Array.isArray(r)?e.jsx(u,{value:r,depth:t}):typeof r=="object"?e.jsx(m,{value:r,depth:t}):e.jsx("span",{className:"text-gray-500",children:String(r)})}function m({value:r,depth:t}){const s=Object.keys(r),[c,a]=l.useState(t<2);return s.length===0?e.jsx("span",{className:"text-gray-500",children:"{}"}):e.jsx(d,{open:c,onToggle:()=>a(n=>!n),collapsedLabel:`{…} ${s.length} ${s.length===1?"key":"keys"}`,openBracket:"{",closeBracket:"}",depth:t,children:s.map((n,i)=>e.jsxs("div",{className:"pl-4",children:[e.jsxs("span",{className:"text-rose-700 dark:text-rose-400",children:['"',n,'"']}),e.jsx("span",{className:"text-gray-500",children:": "}),e.jsx(o,{value:r[n],depth:t+1}),i<s.length-1?e.jsx("span",{className:"text-gray-500",children:","}):null]},n))})}function u({value:r,depth:t}){const[s,c]=l.useState(t<2);return r.length===0?e.jsx("span",{className:"text-gray-500",children:"[]"}):e.jsx(d,{open:s,onToggle:()=>c(a=>!a),collapsedLabel:`[…] ${r.length} ${r.length===1?"item":"items"}`,openBracket:"[",closeBracket:"]",depth:t,children:r.map((a,n)=>e.jsxs("div",{className:"pl-4",children:[e.jsx(o,{value:a,depth:t+1}),n<r.length-1?e.jsx("span",{className:"text-gray-500",children:","}):null]},n))})}function d({open:r,onToggle:t,collapsedLabel:s,openBracket:c,closeBracket:a,depth:n,children:i}){return e.jsxs("span",{children:[e.jsx("button",{type:"button",onClick:t,"aria-expanded":r,className:"inline-flex items-center align-baseline text-gray-500 hover:text-gray-800 dark:hover:text-gray-200",children:e.jsx(g,{className:`h-3 w-3 shrink-0 transition-transform ${r?"rotate-90":""}`,"aria-hidden":!0})}),e.jsx("span",{className:"text-gray-500",children:c}),r?e.jsxs(e.Fragment,{children:[i,e.jsx("div",{className:n===0?"":"pl-0",children:e.jsx("span",{className:"text-gray-500",children:a})})]}):e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"px-1 text-gray-500",children:s}),e.jsx("span",{className:"text-gray-500",children:a})]})]})}export{N as default};
|