Files
unraid-podman/webui
maggesandClaude Sonnet 5 8ac9cde621 Add Pod lifecycle management, fix nav registration and context-menu bugs
Pods panel could previously only list pods - there was no way to create
one, start/stop/restart it, or attach a container to it from the UI.
Adds a "New Pod" modal (name + port mappings), a per-pod lifecycle menu
(start/stop/restart/remove), and an optional "Pod" field on the Create
Container modal to join an existing pod's network namespace. Backend
verified live against the real podman socket (/pods/create, /pods/{name}/
restart, container "pod" field).

Also fixes three real bugs found via live testing:
- Podman.page used Menu="Podman" instead of Menu="Tasks:<rank>", so the
  plugin never actually appeared in Unraid's top navigation (traced through
  PageBuilder.php/DefaultPageLayout.php/Navigation/Main.php - only pages
  registered under "Tasks" become top-level tabs).
- app.js's shared context-menu component mis-mapped every item positioned
  after a 'separator' entry to the wrong DOM element (an off-by-one against
  menu.children, which includes the separator <div>s) - so "Remove", which
  always sits after a separator, silently did nothing when clicked. Fixed
  by indexing into querySelectorAll('button') instead.
- That same menu was positioned via "position: absolute" math that assumed
  a viewport-relative containing block, but Unraid's own page wrapper
  (webGui/styles/default-base.css's ".content") sets position:relative,
  so the menu rendered far from its anchor button. Switched to
  "position: fixed" with viewport-relative coordinates.

Incidentally, pods add a hidden "infra" container that was leaking into
the plain Containers list with no working lifecycle of its own (always
"running", so its own Remove was permanently disabled) - now filtered out
via libpod's IsInfra flag. And every action-buttons table cell used
"display: flex" directly on the <td>, which browsers can size
inconsistently row to row - moved onto an inner wrapper div instead, and
bumped .podman-btn-icon's touch target size.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 16:26:49 +00:00
..

webui/

Dynamix-style WebUI pages, following Unraid's plugin GUI convention of /usr/local/emhttp/plugins/<name>/. webui/plugins/podman/ is staged to that path by the unraid-podman scaffolding package (see packages/unraid-podman/unraid-podman.SlackBuild), which podman.plg installs alongside the other ten packages.

Status: implemented, covering all ten sections from docs/ARCHITECTURE.md, section 18: Dashboard, Containers, Pods, Images, Volumes, Networks, Logs, Terminal, Compose, Settings. Not yet exercised against a real Unraid/Podman install — see docs/ROADMAP.md for what "implemented" does and doesn't cover yet.

webui/mockups/prototype.html is the static, non-PHP clickable mockup this implementation was built against — kept as the visual reference; it is not staged into the package.

Structure

webui/
├── mockups/
│   └── prototype.html         # static approved mockup, not shipped
└── plugins/
    └── podman/
        ├── Podman.page          # page shell: header, sub-nav, one container per panel
        ├── include/
        │   ├── PodmanClient.php # libpod REST API client (talks to podman.sock only)
        │   ├── Config.php       # reads podman.cfg (mirrors podman-common.sh)
        │   ├── bootstrap.php    # shared include + error handling for ajax/*.php
        │   └── helpers.php      # formatting + JSON-response helpers
        ├── ajax/                 # one endpoint per resource, each require()s bootstrap.php
        │   ├── containers.php    # list/start/stop/restart/remove/logs
        │   ├── pods.php
        │   ├── images.php
        │   ├── volumes.php
        │   ├── networks.php
        │   ├── exec.php          # Terminal — see its header comment for API scope
        │   ├── compose.php       # Compose — the one deliberate CLI exception, see header
        │   ├── settings.php      # plugin's own config, not a libpod resource
        │   └── system.php        # Dashboard aggregation
        ├── javascript/
        │   ├── app.js             # shared AJAX helper + sub-tab router
        │   └── <panel>.js         # one module per panel, registers with app.js
        ├── styles/podman.css      # design tokens ported 1:1 from the mockup
        ├── event/                  # official Unraid array-event hooks (see plugin/event/)
        └── images/                  # plugin icon assets

Design constraints (see ARCHITECTURE.md for full rationale)

  • Every panel talks to podman system service over its Unix socket via PodmanClient — no exec()/shell_exec() of the podman binary anywhere in include/ or in the Containers/Pods/Images/Volumes/Networks/ Logs endpoints.
  • Two documented, deliberate exceptions, not oversights:
    • ajax/exec.php (Terminal) uses the real exec REST API, but as one-command-in/output-out rather than a true interactive PTY — libpod's interactive exec needs a persistent hijacked connection that doesn't fit PHP-FPM's request lifecycle. See that file's header comment.
    • ajax/compose.php (Compose) shells out to the podman compose CLI via proc_open() with an argv array (never a shell string) — because no REST endpoint for Compose exists in libpod at all. See that file's header comment.
  • The API socket is root-equivalent; no unauthenticated network exposure beyond what Unraid's own WebUI auth already provides — see .github/SECURITY.md.
  • Dark/light mode via CSS custom properties (prefers-color-scheme + [data-theme] override), matching Unraid's own theme mechanism — no separate theme toggle inside the plugin page.