devpi-admin 1.0.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.
- devpi_admin-1.0.0/.gitignore +15 -0
- devpi_admin-1.0.0/LICENSE +21 -0
- devpi_admin-1.0.0/PKG-INFO +154 -0
- devpi_admin-1.0.0/README.md +133 -0
- devpi_admin-1.0.0/pyproject.toml +51 -0
- devpi_admin-1.0.0/src/devpi_admin/__init__.py +4 -0
- devpi_admin-1.0.0/src/devpi_admin/_version.py +24 -0
- devpi_admin-1.0.0/src/devpi_admin/main.py +70 -0
- devpi_admin-1.0.0/src/devpi_admin/static/css/style.css +1450 -0
- devpi_admin-1.0.0/src/devpi_admin/static/index.html +54 -0
- devpi_admin-1.0.0/src/devpi_admin/static/js/api.js +87 -0
- devpi_admin-1.0.0/src/devpi_admin/static/js/app.js +1661 -0
- devpi_admin-1.0.0/src/devpi_admin/static/js/marked.min.js +69 -0
- devpi_admin-1.0.0/src/devpi_admin/static/js/theme.js +47 -0
- devpi_admin-1.0.0/tests/__init__.py +8 -0
- devpi_admin-1.0.0/tests/test_package.py +52 -0
- devpi_admin-1.0.0/tests/test_tween.py +60 -0
- devpi_admin-1.0.0/tests/test_wants_html.py +52 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pavel Revak <pavelrevak@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: devpi-admin
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Modern web UI plugin for devpi-server — drop-in replacement for devpi-web
|
|
5
|
+
Author-email: Pavel Revak <pavelrevak@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: admin,devpi,pypi,ui,web
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Framework :: Pyramid
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Classifier: Topic :: System :: Software Distribution
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Requires-Dist: devpi-server>=6.0
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# devpi-admin
|
|
23
|
+
|
|
24
|
+
A modern web UI plugin for [devpi-server](https://devpi.net/) — a drop-in replacement for
|
|
25
|
+
`devpi-web`. Ships as a Python package that registers itself as a devpi-server plugin via the
|
|
26
|
+
standard entry point mechanism, so a single `pip install devpi-admin` is enough.
|
|
27
|
+
|
|
28
|
+
The UI itself is a bundled single-page application (pure HTML + CSS + vanilla JavaScript, no
|
|
29
|
+
build step) served under `/+admin/`. All devpi REST API endpoints remain untouched — the SPA
|
|
30
|
+
talks to the standard devpi JSON API directly.
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- **Dashboard** with server info and cache metrics (`/+status`)
|
|
35
|
+
- **Index browser** with visual cards color-coded by type (stage / volatile / mirror)
|
|
36
|
+
- **Users** management — create, edit, delete (admin only)
|
|
37
|
+
- **Index** management — create / edit / delete, configure `bases` (drag & drop priority,
|
|
38
|
+
transitive inheritance detection), `volatile`, `acl_upload` (tag picker), `mirror_url`
|
|
39
|
+
- **Package browser** with client-side search and pagination, including an explicit
|
|
40
|
+
download prompt for huge mirrors (e.g. `root/pypi`'s ~780 k packages / 17 MB index)
|
|
41
|
+
- **Package detail** in a PyPI-like layout: sidebar with metadata, version list, install
|
|
42
|
+
command, file downloads; main area renders the README (markdown via `marked.js`)
|
|
43
|
+
- **Copy-to-clipboard `pip install`** commands with a `pip.conf` toggle
|
|
44
|
+
(short form vs. full `--index-url` / `--trusted-host`)
|
|
45
|
+
- **`pip.conf` generator** — download a ready-to-use config per index
|
|
46
|
+
- **Anonymous browsing** — visitors can explore public indexes without logging in; admin
|
|
47
|
+
actions appear only after authentication
|
|
48
|
+
- **Dark / light / auto theme**, responsive mobile menu, ESC + outside-click dismissal of
|
|
49
|
+
dialogs
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install devpi-admin
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This pulls in `devpi-server` as a dependency. If you are using devpi in a dedicated venv
|
|
58
|
+
(recommended), install the plugin into the same venv:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
/var/lib/pypi/venv/bin/pip install devpi-admin
|
|
62
|
+
systemctl --user restart devpi # or however you run devpi-server
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
You should uninstall `devpi-web` first — `devpi-admin` provides all the web UI you need:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip uninstall devpi-web
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
After restart, open:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
http://<your-devpi-host>:3141/
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Browser visits to `/` are redirected to `/+admin/`, which serves the SPA. Direct links like
|
|
80
|
+
`http://<host>:3141/+admin/#packages/ci/testing` work and can be bookmarked.
|
|
81
|
+
|
|
82
|
+
devpi CLI tools and other JSON clients are unaffected — they send `Accept: application/json`
|
|
83
|
+
and bypass the redirect.
|
|
84
|
+
|
|
85
|
+
## How it works
|
|
86
|
+
|
|
87
|
+
`devpi-admin` registers a `devpi_server` entry point that hooks into `devpiserver_pyramid_configure`
|
|
88
|
+
to:
|
|
89
|
+
|
|
90
|
+
1. Serve the bundled static assets under `/+admin/` via a Pyramid static view.
|
|
91
|
+
2. Add an explicit view at `/+admin/` that returns `index.html` (so the directory itself
|
|
92
|
+
resolves to the SPA entry point).
|
|
93
|
+
3. Install a tween that redirects HTML browser requests on `/` to `/+admin/` while leaving
|
|
94
|
+
JSON requests intact.
|
|
95
|
+
|
|
96
|
+
No changes are made to the devpi REST API.
|
|
97
|
+
|
|
98
|
+
## Requirements
|
|
99
|
+
|
|
100
|
+
- Python 3.9+
|
|
101
|
+
- devpi-server 6.0+
|
|
102
|
+
- A browser with ES6 support and `Promise`, `fetch`, `sessionStorage`
|
|
103
|
+
|
|
104
|
+
## Routes (UI)
|
|
105
|
+
|
|
106
|
+
Routing is hash-based, so any of these URLs can be bookmarked or shared:
|
|
107
|
+
|
|
108
|
+
- `/+admin/#` — Status dashboard (default)
|
|
109
|
+
- `/+admin/#indexes` — all indexes
|
|
110
|
+
- `/+admin/#indexes/<user>` — filtered to one user
|
|
111
|
+
- `/+admin/#packages/<user>/<index>` — packages in an index
|
|
112
|
+
- `/+admin/#package/<user>/<index>/<name>` — package detail (latest version)
|
|
113
|
+
- `/+admin/#package/<user>/<index>/<name>?version=<ver>` — specific version
|
|
114
|
+
- `/+admin/#users` — users admin (requires login)
|
|
115
|
+
|
|
116
|
+
## Project layout
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
devpi-admin/
|
|
120
|
+
├── pyproject.toml
|
|
121
|
+
├── README.md
|
|
122
|
+
└── src/
|
|
123
|
+
└── devpi_admin/
|
|
124
|
+
├── __init__.py
|
|
125
|
+
├── main.py — Pyramid hooks & tween
|
|
126
|
+
└── static/
|
|
127
|
+
├── index.html — SPA entry
|
|
128
|
+
├── css/style.css
|
|
129
|
+
└── js/
|
|
130
|
+
├── api.js — devpi REST wrapper
|
|
131
|
+
├── theme.js — theme toggle (light/dark/auto)
|
|
132
|
+
├── marked.min.js — vendored markdown renderer
|
|
133
|
+
└── app.js — routing, views, rendering
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
git clone <repo>
|
|
140
|
+
cd devpi-admin
|
|
141
|
+
pip install -e .
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The static files live at `src/devpi_admin/static/` and can be edited in place — changes
|
|
145
|
+
show up on the next browser reload, no restart of devpi-server required (static views
|
|
146
|
+
read from disk on each request).
|
|
147
|
+
|
|
148
|
+
## Author
|
|
149
|
+
|
|
150
|
+
Pavel Revak <pavelrevak@gmail.com>
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# devpi-admin
|
|
2
|
+
|
|
3
|
+
A modern web UI plugin for [devpi-server](https://devpi.net/) — a drop-in replacement for
|
|
4
|
+
`devpi-web`. Ships as a Python package that registers itself as a devpi-server plugin via the
|
|
5
|
+
standard entry point mechanism, so a single `pip install devpi-admin` is enough.
|
|
6
|
+
|
|
7
|
+
The UI itself is a bundled single-page application (pure HTML + CSS + vanilla JavaScript, no
|
|
8
|
+
build step) served under `/+admin/`. All devpi REST API endpoints remain untouched — the SPA
|
|
9
|
+
talks to the standard devpi JSON API directly.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Dashboard** with server info and cache metrics (`/+status`)
|
|
14
|
+
- **Index browser** with visual cards color-coded by type (stage / volatile / mirror)
|
|
15
|
+
- **Users** management — create, edit, delete (admin only)
|
|
16
|
+
- **Index** management — create / edit / delete, configure `bases` (drag & drop priority,
|
|
17
|
+
transitive inheritance detection), `volatile`, `acl_upload` (tag picker), `mirror_url`
|
|
18
|
+
- **Package browser** with client-side search and pagination, including an explicit
|
|
19
|
+
download prompt for huge mirrors (e.g. `root/pypi`'s ~780 k packages / 17 MB index)
|
|
20
|
+
- **Package detail** in a PyPI-like layout: sidebar with metadata, version list, install
|
|
21
|
+
command, file downloads; main area renders the README (markdown via `marked.js`)
|
|
22
|
+
- **Copy-to-clipboard `pip install`** commands with a `pip.conf` toggle
|
|
23
|
+
(short form vs. full `--index-url` / `--trusted-host`)
|
|
24
|
+
- **`pip.conf` generator** — download a ready-to-use config per index
|
|
25
|
+
- **Anonymous browsing** — visitors can explore public indexes without logging in; admin
|
|
26
|
+
actions appear only after authentication
|
|
27
|
+
- **Dark / light / auto theme**, responsive mobile menu, ESC + outside-click dismissal of
|
|
28
|
+
dialogs
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install devpi-admin
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This pulls in `devpi-server` as a dependency. If you are using devpi in a dedicated venv
|
|
37
|
+
(recommended), install the plugin into the same venv:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
/var/lib/pypi/venv/bin/pip install devpi-admin
|
|
41
|
+
systemctl --user restart devpi # or however you run devpi-server
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You should uninstall `devpi-web` first — `devpi-admin` provides all the web UI you need:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip uninstall devpi-web
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
After restart, open:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
http://<your-devpi-host>:3141/
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Browser visits to `/` are redirected to `/+admin/`, which serves the SPA. Direct links like
|
|
59
|
+
`http://<host>:3141/+admin/#packages/ci/testing` work and can be bookmarked.
|
|
60
|
+
|
|
61
|
+
devpi CLI tools and other JSON clients are unaffected — they send `Accept: application/json`
|
|
62
|
+
and bypass the redirect.
|
|
63
|
+
|
|
64
|
+
## How it works
|
|
65
|
+
|
|
66
|
+
`devpi-admin` registers a `devpi_server` entry point that hooks into `devpiserver_pyramid_configure`
|
|
67
|
+
to:
|
|
68
|
+
|
|
69
|
+
1. Serve the bundled static assets under `/+admin/` via a Pyramid static view.
|
|
70
|
+
2. Add an explicit view at `/+admin/` that returns `index.html` (so the directory itself
|
|
71
|
+
resolves to the SPA entry point).
|
|
72
|
+
3. Install a tween that redirects HTML browser requests on `/` to `/+admin/` while leaving
|
|
73
|
+
JSON requests intact.
|
|
74
|
+
|
|
75
|
+
No changes are made to the devpi REST API.
|
|
76
|
+
|
|
77
|
+
## Requirements
|
|
78
|
+
|
|
79
|
+
- Python 3.9+
|
|
80
|
+
- devpi-server 6.0+
|
|
81
|
+
- A browser with ES6 support and `Promise`, `fetch`, `sessionStorage`
|
|
82
|
+
|
|
83
|
+
## Routes (UI)
|
|
84
|
+
|
|
85
|
+
Routing is hash-based, so any of these URLs can be bookmarked or shared:
|
|
86
|
+
|
|
87
|
+
- `/+admin/#` — Status dashboard (default)
|
|
88
|
+
- `/+admin/#indexes` — all indexes
|
|
89
|
+
- `/+admin/#indexes/<user>` — filtered to one user
|
|
90
|
+
- `/+admin/#packages/<user>/<index>` — packages in an index
|
|
91
|
+
- `/+admin/#package/<user>/<index>/<name>` — package detail (latest version)
|
|
92
|
+
- `/+admin/#package/<user>/<index>/<name>?version=<ver>` — specific version
|
|
93
|
+
- `/+admin/#users` — users admin (requires login)
|
|
94
|
+
|
|
95
|
+
## Project layout
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
devpi-admin/
|
|
99
|
+
├── pyproject.toml
|
|
100
|
+
├── README.md
|
|
101
|
+
└── src/
|
|
102
|
+
└── devpi_admin/
|
|
103
|
+
├── __init__.py
|
|
104
|
+
├── main.py — Pyramid hooks & tween
|
|
105
|
+
└── static/
|
|
106
|
+
├── index.html — SPA entry
|
|
107
|
+
├── css/style.css
|
|
108
|
+
└── js/
|
|
109
|
+
├── api.js — devpi REST wrapper
|
|
110
|
+
├── theme.js — theme toggle (light/dark/auto)
|
|
111
|
+
├── marked.min.js — vendored markdown renderer
|
|
112
|
+
└── app.js — routing, views, rendering
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Development
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
git clone <repo>
|
|
119
|
+
cd devpi-admin
|
|
120
|
+
pip install -e .
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The static files live at `src/devpi_admin/static/` and can be edited in place — changes
|
|
124
|
+
show up on the next browser reload, no restart of devpi-server required (static views
|
|
125
|
+
read from disk on each request).
|
|
126
|
+
|
|
127
|
+
## Author
|
|
128
|
+
|
|
129
|
+
Pavel Revak <pavelrevak@gmail.com>
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "devpi-admin"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Modern web UI plugin for devpi-server — drop-in replacement for devpi-web"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Pavel Revak", email = "pavelrevak@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["devpi", "pypi", "admin", "web", "ui"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Framework :: Pyramid",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Intended Audience :: System Administrators",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Topic :: Software Development :: Libraries",
|
|
25
|
+
"Topic :: System :: Software Distribution",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"devpi-server>=6.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.entry-points.devpi_server]
|
|
32
|
+
devpi-admin = "devpi_admin.main"
|
|
33
|
+
|
|
34
|
+
[tool.hatch.version]
|
|
35
|
+
source = "vcs"
|
|
36
|
+
fallback-version = "0.0.0"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.hooks.vcs]
|
|
39
|
+
version-file = "src/devpi_admin/_version.py"
|
|
40
|
+
|
|
41
|
+
[tool.hatch.build.targets.wheel]
|
|
42
|
+
packages = ["src/devpi_admin"]
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.sdist]
|
|
45
|
+
include = [
|
|
46
|
+
"src/devpi_admin",
|
|
47
|
+
"tests",
|
|
48
|
+
"README.md",
|
|
49
|
+
"pyproject.toml",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '1.0.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""devpi-admin: web UI plugin for devpi-server.
|
|
2
|
+
|
|
3
|
+
Installs a single-page application that replaces devpi-web. The SPA is served
|
|
4
|
+
under ``/+admin/`` and browser requests to ``/`` are redirected there. All
|
|
5
|
+
existing devpi REST API endpoints are left untouched — the JS app talks to
|
|
6
|
+
the standard devpi JSON API (``/+login``, ``/<user>/<index>``, ...).
|
|
7
|
+
"""
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from pyramid.httpexceptions import HTTPFound
|
|
11
|
+
from pyramid.response import FileResponse
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
STATIC_DIR = Path(__file__).parent / "static"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def devpiserver_get_features():
|
|
18
|
+
# Advertise the plugin to devpi-server
|
|
19
|
+
return {"devpi-admin"}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def devpiserver_pyramid_configure(config, pyramid_config):
|
|
23
|
+
# Serve bundled static assets (index.html, css/, js/) under /+admin/.
|
|
24
|
+
pyramid_config.add_static_view(
|
|
25
|
+
name="+admin", path="devpi_admin:static")
|
|
26
|
+
|
|
27
|
+
# Serve index.html on /+admin/ (with trailing slash). add_static_view
|
|
28
|
+
# does not auto-resolve directory index files.
|
|
29
|
+
pyramid_config.add_route("devpi_admin_spa", "/+admin/")
|
|
30
|
+
pyramid_config.add_view(_serve_index, route_name="devpi_admin_spa")
|
|
31
|
+
|
|
32
|
+
# Bare /+admin (no slash) → redirect so relative asset URLs resolve.
|
|
33
|
+
pyramid_config.add_route("devpi_admin_spa_noslash", "/+admin")
|
|
34
|
+
pyramid_config.add_view(
|
|
35
|
+
lambda request: HTTPFound("/+admin/"),
|
|
36
|
+
route_name="devpi_admin_spa_noslash")
|
|
37
|
+
|
|
38
|
+
# Redirect browser visits to "/" to the SPA. Other routes (JSON API
|
|
39
|
+
# calls, CLI requests) pass through untouched because they send
|
|
40
|
+
# Accept: application/json.
|
|
41
|
+
pyramid_config.add_tween(
|
|
42
|
+
"devpi_admin.main.devpi_admin_tween_factory")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _serve_index(request):
|
|
46
|
+
return FileResponse(
|
|
47
|
+
str(STATIC_DIR / "index.html"),
|
|
48
|
+
request=request,
|
|
49
|
+
content_type="text/html")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def devpi_admin_tween_factory(handler, registry):
|
|
53
|
+
def tween(request):
|
|
54
|
+
if (request.method == "GET"
|
|
55
|
+
and request.path == "/"
|
|
56
|
+
and _wants_html(request)):
|
|
57
|
+
return HTTPFound("/+admin/")
|
|
58
|
+
return handler(request)
|
|
59
|
+
return tween
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _wants_html(request):
|
|
63
|
+
accept = request.headers.get("Accept") or ""
|
|
64
|
+
if not accept:
|
|
65
|
+
return False
|
|
66
|
+
# Browsers send "text/html,application/xhtml+xml,...". JSON clients
|
|
67
|
+
# (our SPA, devpi CLI) send "application/json".
|
|
68
|
+
if "application/json" in accept and "text/html" not in accept:
|
|
69
|
+
return False
|
|
70
|
+
return "text/html" in accept or "*/*" in accept
|