Add Apps/Store tab, template WebUI/URL import, container RO volumes/device passthrough/run-as-user, and in-app confirm dialogs
Replaces every native confirm() with a shared P.confirm() modal (a hung native dialog was found live to block the whole tab, including auto-refresh, and once even double-confirmed an unrelated deletion). Also fixes Edit Container silently resetting to Bridge/blanking the Static IP for any container on a custom network, and a context menu losing its anchor to a mid-read auto-refresh. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,99 @@ see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#52-build-strategie)).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- Edit Container always reset the Network dropdown to "Bridge" and blanked
|
||||
the Static IP field, even for a container actually on a custom/macvlan
|
||||
network with a real IP — `HostConfig.NetworkMode` turns out to just say
|
||||
"bridge" regardless of what a container is actually attached to via a
|
||||
custom network (verified live: a running container on "Lan" reported
|
||||
NetworkMode "bridge" while `NetworkSettings.Networks` only had a "Lan"
|
||||
entry, no "bridge" one at all). The real network name now comes from
|
||||
that one `NetworkSettings.Networks` key instead, except when it's
|
||||
podman's own literal default bridge network (named "podman", not
|
||||
"bridge") — found while investigating why Sonarr's real static IP never
|
||||
showed up in its own Edit form.
|
||||
- A row's context menu (opened from a container's name or its "⋮") kept
|
||||
the ~2s auto-refresh running underneath it — found live: leaving the
|
||||
menu open longer than that (reading it, or opening "Move to Folder"
|
||||
after a pause) let a refresh replace the whole table's rows in the
|
||||
background, so the menu's anchor button was no longer the one actually
|
||||
on screen, and a submenu opened from it then positioned itself
|
||||
wherever that stale anchor now was instead of anywhere sensible.
|
||||
Auto-refresh now also pauses while any context menu is open, the same
|
||||
way it already paused for an open modal.
|
||||
|
||||
### Added
|
||||
- Create/Edit Container: "Run as user (optional)" overrides the image's
|
||||
own default user (e.g. `99:100`) — found live migrating a real
|
||||
container (Seerr) that Docker had run as `--user 99:100` to match its
|
||||
bind-mounted appdata's ownership; without this field, podman fell back
|
||||
to the image's own `USER node` (UID 1000), which couldn't write to
|
||||
files/directories owned by `nobody:users`. Pre-fills from an existing
|
||||
container's own `Config.User` when editing.
|
||||
- Clicking a container's name in the Containers table now opens its row
|
||||
menu (Details/Pause/Kill/Rename/Edit/Remove), matching how a folder's
|
||||
member chips already worked — Details becomes just the first menu item
|
||||
again, consistent everywhere a container is represented, rather than
|
||||
only inside a folder.
|
||||
- Create/Edit Container: volumes can now be marked read-only (a "RO"
|
||||
checkbox per row), and a new "Device passthrough" field passes an
|
||||
arbitrary host device (e.g. a USB serial adapter like `/dev/ttyACM0`)
|
||||
through at the same path inside the container — the existing GPU
|
||||
passthrough field is unchanged and stays the right choice for
|
||||
`/dev/dri/*`. Both were verified live against podman's own API before
|
||||
wiring them up (`RW:false` on the resulting mount, and the device
|
||||
showing up as `PathOnHost`/`PathInContainer`). Device paths are
|
||||
restricted to `/dev/...` (no `..`) — this goes straight into a podman
|
||||
create request, not anywhere it could reach untrusted input otherwise.
|
||||
Read-only also round-trips through templates now (dockerMan's own
|
||||
`Mode="ro"` convention on a `Path` Config — found in the wild on a real
|
||||
template that mounts `/mnt/user` read-only for a storage-stats
|
||||
sidecar). Generic device passthrough is a container-only field for now,
|
||||
not yet part of the template schema.
|
||||
- Templates now carry a container's WebUI URL through save/export/import
|
||||
too (`<WebUI>`, the same tag Unraid's own Docker templates already use
|
||||
for this) — "Use template" now pre-fills the WebUI URL field, and this
|
||||
applies to existing Community Applications/dockerMan templates on
|
||||
import too, not just ones authored by this plugin.
|
||||
- Templates: "Import from a URL" (e.g. a raw GitHub link to a Community
|
||||
Applications template), fetched server-side rather than requiring
|
||||
copy-paste. The fetch only allows plain http(s) to a hostname that
|
||||
resolves exclusively to public addresses (checked before the request,
|
||||
then pinned via curl's `CURLOPT_RESOLVE` so a DNS answer can't change
|
||||
between that check and the actual connection), doesn't follow
|
||||
redirects, and caps the response size — see
|
||||
`template_fetch_url()` in `ajax/templates.php`.
|
||||
- The Templates tab is now "Apps", with a Store/My Templates toggle.
|
||||
Store browses/searches Community Applications' own public app feed
|
||||
directly (the same catalog CA's own plugin is built on — see
|
||||
`ca_feed_search()` in `ajax/templates.php`), paginated (24/page, with
|
||||
Prev/Next) rather than a single capped-length list. Browsing (no search
|
||||
term) defaults to Newest-first (by the feed's own FirstSeen timestamp —
|
||||
when CA's feed first picked the template up), with a toggle to
|
||||
alphabetical; an actual search is always alphabetical regardless of that
|
||||
toggle — the only other candidate signal, the feed's own "downloads"
|
||||
figure, turns out to just be the underlying Docker image's Docker Hub
|
||||
pull count (found live: dozens of unrelated templates that all happen to
|
||||
wrap the official nginx/postgres/redis images share the exact same,
|
||||
enormous number), which would make search results look ranked by
|
||||
relevance while really just favoring whichever match wraps the
|
||||
most-pulled base image. "Install" fetches + imports an app the same way
|
||||
pasting its template URL always did, then opens it straight in the
|
||||
Create Container form, pre-filled — the same experience "Use" already
|
||||
gives a saved template, since installing one also saves it as one. My
|
||||
Templates is this plugin's own saved-template grid, unchanged, with
|
||||
"Import Template" (paste XML / a URL / one of Unraid's own existing
|
||||
local Docker templates) still a modal off of it.
|
||||
- A shared in-app confirm dialog (`P.confirm()` in `app.js`) replaces
|
||||
every browser-native `confirm()` across the whole plugin (containers,
|
||||
templates, compose, images, volumes, networks, pods, settings). A
|
||||
native `confirm()` blocks the entire tab until dismissed — including
|
||||
this plugin's own auto-refresh — and found live to be an actual
|
||||
liability: a hung dialog blocked further interaction outright, and in
|
||||
one case a stray keypress meant to dismiss it ended up confirming a
|
||||
second, unrelated deletion too.
|
||||
|
||||
### Fixed
|
||||
- `podman-verify-packages.sh`/`podman-update-packages.sh` reported every
|
||||
single package as "not installed" right after a genuinely successful
|
||||
|
||||
Reference in New Issue
Block a user