devpi-admin 1.0.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.
- devpi_admin/__init__.py +4 -0
- devpi_admin/_version.py +24 -0
- devpi_admin/main.py +70 -0
- devpi_admin/static/css/style.css +1450 -0
- devpi_admin/static/index.html +54 -0
- devpi_admin/static/js/api.js +87 -0
- devpi_admin/static/js/app.js +1661 -0
- devpi_admin/static/js/marked.min.js +69 -0
- devpi_admin/static/js/theme.js +47 -0
- devpi_admin-1.0.0.dist-info/METADATA +154 -0
- devpi_admin-1.0.0.dist-info/RECORD +14 -0
- devpi_admin-1.0.0.dist-info/WHEEL +4 -0
- devpi_admin-1.0.0.dist-info/entry_points.txt +2 -0
- devpi_admin-1.0.0.dist-info/licenses/LICENSE +21 -0
devpi_admin/__init__.py
ADDED
devpi_admin/_version.py
ADDED
|
@@ -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
|
devpi_admin/main.py
ADDED
|
@@ -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
|