Modern web UI plugin for devpi-server — drop-in replacement for devpi-web
Project description
devpi-admin
A modern web UI plugin for devpi-server — a drop-in replacement for
devpi-web. Ships as a Python package that registers itself as a devpi-server plugin via the
standard entry point mechanism, so a single pip install devpi-admin is enough.
The UI itself is a bundled single-page application (pure HTML + CSS + vanilla JavaScript, no
build step) served under /+admin/. All devpi REST API endpoints remain untouched — the SPA
talks to the standard devpi JSON API directly.
Features
Dashboard
- Server info with version of devpi-server and all installed plugins (auto-detected)
- Cache metrics with hit-rate bars (storage, changelog, relpath caches)
- Whoosh search index queue status
- Replica status (master only) — per-replica cards with online/offline badge, serial lag, and last-seen timestamp; visible only when replicas are connected
Indexes
- Visual cards color-coded by type: green (stage), amber (volatile stage), blue (mirror)
pip installcommand with copy-to-clipboard (click to copy, green flash feedback)pip.conftoggle — switch between short form and full--index-url/--trusted-hostpip.confgenerator — download a ready-to-use config per index- Create / edit / delete indexes via modal dialogs
baseseditor with drag & drop priority ordering and transitive inheritance displayacl_uploadtag picker with user selection dropdownvolatile,mirror_url,titleconfiguration
Users
- Create, edit (email, password), delete users (admin only)
Packages
- Client-side search with PEP 503 name normalization
- Mirror indexes: shows only cached packages (filesystem scan, no 17 MB index download); "Download full index" button available for complete browse
- Package cards with latest version and
pip installcommand
Package detail (PyPI-like layout)
- Sidebar: metadata (author, license, Python version, keywords, platform, maintainer,
extras, project URLs, dependencies),
pip installcommand, file downloads with upload dates - Version list: cached versions shown normally, uncached versions link to pypi.org (↗); "Load all versions" button for mirrors
- README: rendered markdown (via
marked.js); fetched from PyPI.org for mirror packages where devpi doesn't cache the description
General
- Anonymous browsing — visitors can explore public indexes without logging in; admin actions (create/edit/delete) appear only after authentication
- Dark / light / auto theme with half-circle icon for auto mode
- Responsive mobile menu with hamburger toggle
- ESC + outside-click dismissal for modals, dropdown menus, mobile menu
- Login via modal — no separate login page
Plugin API endpoints
In addition to serving the SPA, devpi-admin registers custom API endpoints under
/+admin-api/ for features that the standard devpi REST API doesn't provide efficiently:
| Endpoint | Method | Description |
|---|---|---|
/+admin-api/cached/{user}/{index} |
GET | List cached package names for a mirror index (filesystem scan) |
/+admin-api/versions/{user}/{index}/{project} |
GET | Version list with cached/uncached distinction |
/+admin-api/versions/{user}/{index}/{project}?all=1 |
GET | Include all upstream versions (mirrors) |
/+admin-api/versiondata/{user}/{index}/{project}/{version} |
GET | Metadata + file links for a single version |
Installation
pip install devpi-admin
This pulls in devpi-server as a dependency. If you are using devpi in a dedicated venv
(recommended), install the plugin into the same venv:
/var/lib/pypi/venv/bin/pip install devpi-admin
systemctl --user restart devpi # or however you run devpi-server
You should uninstall devpi-web — devpi-admin replaces it entirely:
pip uninstall devpi-web
Both plugins can technically coexist but it is not recommended. devpi-admin intercepts /
for HTML requests while devpi-web would still serve its own HTML on other routes like
/<user>/<index>/<package>, leading to a confusing mixed experience.
Usage
After restart, open:
http://<your-devpi-host>:3141/
Browser visits to / are redirected to /+admin/, which serves the SPA. Direct links like
http://<host>:3141/+admin/#packages/ci/testing work and can be bookmarked.
devpi CLI tools and other JSON clients are unaffected — they send Accept: application/json
and bypass the redirect.
How it works
devpi-admin registers a devpi_server entry point that hooks into
devpiserver_pyramid_configure (with @hookimpl from pluggy) to:
- Serve the bundled static assets under
/+admin/via a Pyramid static view. - Add an explicit view at
/+admin/that returnsindex.html. - Register custom API views under
/+admin-api/for cached-package and per-version queries. - Install a tween that redirects HTML browser requests on
/to/+admin/while leaving JSON requests intact.
The plugin uses devpi-server internals (xom.model.getstage, stage.list_versions,
stage.get_versiondata, stage.get_releaselinks) and direct filesystem access
(serverdir/+files/) for the cached-packages API.
Requirements
- Python 3.9+
- devpi-server 6.0+
- A browser with ES6 support (
Promise,fetch,sessionStorage)
Routes (UI)
Routing is hash-based, so any of these URLs can be bookmarked or shared:
| Hash | View |
|---|---|
# |
Status dashboard (default) |
#indexes |
All indexes |
#indexes/<user> |
Indexes filtered by user |
#packages/<user>/<index> |
Packages in an index |
#package/<user>/<index>/<name> |
Package detail (latest cached version) |
#package/<user>/<index>/<name>?version=<ver> |
Specific version |
#users |
User management (requires login) |
Project layout
devpi-admin/
├── pyproject.toml
├── README.md
├── LICENSE
├── .github/workflows/
│ ├── tests.yml — CI on push/PR (Python 3.10 + 3.14)
│ └── publish.yml — publish to PyPI on release
├── src/
│ └── devpi_admin/
│ ├── __init__.py — version (from git tag via hatch-vcs)
│ ├── main.py — Pyramid hooks, tween, API views
│ └── static/
│ ├── index.html — SPA entry point
│ ├── css/style.css
│ └── js/
│ ├── api.js — devpi REST wrapper + auth
│ ├── theme.js — theme toggle (light/dark/auto)
│ ├── marked.min.js — vendored markdown renderer
│ └── app.js — routing, views, rendering
└── tests/
├── test_cached_versions.py — filesystem scan (tmpdir)
├── test_helpers.py — filename parsing, normalization
├── test_hooks.py — pluggy hook registration
├── test_json_safe.py — readonly view conversion
├── test_package.py — entry point, static files
├── test_tween.py — redirect behavior
└── test_wants_html.py — Accept header heuristic
Development
git clone <repo>
cd devpi-admin
python -m venv .venv
.venv/bin/pip install -e .
The static files live at src/devpi_admin/static/ and can be edited in place — changes
show up on the next browser reload, no restart of devpi-server required (static views
read from disk on each request). Python changes (main.py) require a devpi-server restart.
Run the unit tests:
PYTHONWARNINGS="ignore::UserWarning" python -m unittest discover -v tests/
(The PYTHONWARNINGS shim hides an unrelated deprecation warning emitted by Pyramid 2.1
when it imports pkg_resources.)
Releasing
Version is derived from the git tag via hatch-vcs. To release:
git tag v0.1.0 && git push --tags- On GitHub: Releases → Draft new release → select tag → Publish
- The
publish.ymlworkflow runs tests, builds wheel+sdist, and uploads to PyPI via trusted publishing (no API tokens needed — configure the GitHub environmentpypiin PyPI settings).
Author
Pavel Revak pavelrevak@gmail.com
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file devpi_admin-1.2.0.tar.gz.
File metadata
- Download URL: devpi_admin-1.2.0.tar.gz
- Upload date:
- Size: 57.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f477cfe3c394f7db17e5b7bec051733da50d80c66ea04f7224bd96d2eab3e81e
|
|
| MD5 |
db122e5bb575535595b6ecf473af3e3a
|
|
| BLAKE2b-256 |
51dd5b890eb48b9be6a779eeeb69155ad2957005e47b18f62beae0885d8a96d8
|
Provenance
The following attestation bundles were made for devpi_admin-1.2.0.tar.gz:
Publisher:
publish.yml on pavelrevak/devpi-admin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
devpi_admin-1.2.0.tar.gz -
Subject digest:
f477cfe3c394f7db17e5b7bec051733da50d80c66ea04f7224bd96d2eab3e81e - Sigstore transparency entry: 1340705762
- Sigstore integration time:
-
Permalink:
pavelrevak/devpi-admin@34be8ff92eba905b86cb0d992b6ba76515bbf972 -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/pavelrevak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@34be8ff92eba905b86cb0d992b6ba76515bbf972 -
Trigger Event:
release
-
Statement type:
File details
Details for the file devpi_admin-1.2.0-py3-none-any.whl.
File metadata
- Download URL: devpi_admin-1.2.0-py3-none-any.whl
- Upload date:
- Size: 49.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f6654dd335a172b47f734ca16c40d0e1d48b43241921b4eb18e87bbc7c48b60
|
|
| MD5 |
f3eac849333c1e5302b32750241f6aa7
|
|
| BLAKE2b-256 |
13b06f89e9ab844d478d43b863eaff3936666e3c980bd2da1e836c440aa36ae8
|
Provenance
The following attestation bundles were made for devpi_admin-1.2.0-py3-none-any.whl:
Publisher:
publish.yml on pavelrevak/devpi-admin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
devpi_admin-1.2.0-py3-none-any.whl -
Subject digest:
4f6654dd335a172b47f734ca16c40d0e1d48b43241921b4eb18e87bbc7c48b60 - Sigstore transparency entry: 1340705769
- Sigstore integration time:
-
Permalink:
pavelrevak/devpi-admin@34be8ff92eba905b86cb0d992b6ba76515bbf972 -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/pavelrevak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@34be8ff92eba905b86cb0d992b6ba76515bbf972 -
Trigger Event:
release
-
Statement type: