Add container create page from the containers list with always-pull.
Release rolling / release (push) Successful in 8m24s

Adds a dedicated blank create form (name, image, always pull, ports,
auto-remove, advanced settings) separate from template Deploy, reuses
deployContainer with pull-if-missing and publish-all-ports support.
This commit is contained in:
Raven Scott
2026-07-15 14:27:05 -04:00
parent bbf0607aaf
commit b185ea7a55
9 changed files with 1055 additions and 24 deletions
+326
View File
@@ -963,6 +963,11 @@
<h2><i class="fas fa-cube"></i>Containers</h2>
<p class="page-subtitle">Lifecycle, logs, stats, and terminals</p>
</div>
<div class="btn-group">
<button type="button" class="btn btn-primary" id="add-container-btn" data-min-role="operator" onclick="navigateToView('add-container')">
<i class="fas fa-plus me-2"></i>Add container
</button>
</div>
</div>
<!-- Container Filter and Search -->
<div class="view-toolbar mb-3">
@@ -1062,6 +1067,327 @@
</div>
</div>
<!-- Add container (blank create — separate from Deploy templates) -->
<div id="add-container-view" class="view hidden">
<div class="container-fluid add-container-page">
<div class="page-header">
<div>
<button type="button" class="btn btn-link text-secondary p-0 mb-1 addc-back-link" onclick="navigateToView('containers')">
<i class="fas fa-arrow-left me-1"></i>Back to containers
</button>
<h2><i class="fas fa-plus-circle"></i>Add container</h2>
<p class="page-subtitle">Create and start a container from an image</p>
</div>
</div>
<form id="add-container-form" class="add-container-form" onsubmit="return false;">
<div class="info-card mb-3">
<h6 class="text-primary mb-3"><i class="fas fa-cube me-2"></i>Image configuration</h6>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="addc-name">Name <span class="text-danger">*</span></label>
<input type="text" id="addc-name" class="form-control bg-dark text-white" placeholder="my-container" required autocomplete="off" maxlength="63">
</div>
<div class="col-md-6">
<label class="form-label" for="addc-image">Image <span class="text-danger">*</span></label>
<input type="text" id="addc-image" class="form-control bg-dark text-white" placeholder="nginx:alpine" required autocomplete="off">
<div class="form-text">Registry and tag included (e.g. ghcr.io/org/app:1.0)</div>
</div>
<div class="col-12">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="addc-always-pull" checked>
<label class="form-check-label" for="addc-always-pull">Always pull the image</label>
</div>
<div class="form-text">When on, pull from the registry before create. When off, use a local image if present.</div>
</div>
</div>
</div>
<div class="info-card mb-3">
<h6 class="text-primary mb-3"><i class="fas fa-network-wired me-2"></i>Network ports</h6>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="addc-publish-all">
<label class="form-check-label" for="addc-publish-all">Publish all exposed network ports to random host ports</label>
</div>
<div id="addc-ports" class="mb-2"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="addc-add-port">
<i class="fas fa-plus me-1"></i>Publish a new network port
</button>
</div>
<div class="info-card mb-3">
<h6 class="text-primary mb-3"><i class="fas fa-play me-2"></i>Actions</h6>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="addc-auto-remove">
<label class="form-check-label" for="addc-auto-remove">Auto remove</label>
</div>
<div class="form-text mb-3">Automatically remove the container when it exits (one-shot jobs).</div>
<div class="d-flex flex-wrap gap-2 align-items-center">
<button type="button" class="btn btn-primary" id="addc-deploy-btn" data-min-role="operator">
<i class="fas fa-rocket me-2"></i>Deploy the container
</button>
<button type="button" class="btn btn-outline-secondary" id="addc-cancel-btn">Cancel</button>
<button type="button" class="btn btn-outline-secondary" id="addc-reset-btn">Reset</button>
</div>
</div>
<div class="info-card mb-3">
<h6 class="text-primary mb-3"><i class="fas fa-sliders-h me-2"></i>Advanced container settings</h6>
<div class="accordion accordion-flush" id="addcAccordion">
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-dark text-white" type="button" data-bs-toggle="collapse" data-bs-target="#addc-cmd-log" aria-expanded="false">
Command &amp; logging
</button>
</h2>
<div id="addc-cmd-log" class="accordion-collapse collapse" data-bs-parent="#addcAccordion">
<div class="accordion-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="addc-command">Command</label>
<input type="text" id="addc-command" class="form-control bg-dark text-white" placeholder="Override image CMD">
</div>
<div class="col-md-6">
<label class="form-label" for="addc-entrypoint">Entrypoint</label>
<input type="text" id="addc-entrypoint" class="form-control bg-dark text-white" placeholder="Override image ENTRYPOINT">
</div>
<div class="col-md-6">
<label class="form-label" for="addc-workdir">Working dir</label>
<input type="text" id="addc-workdir" class="form-control bg-dark text-white" placeholder="/app">
</div>
<div class="col-md-6">
<label class="form-label" for="addc-user">User</label>
<input type="text" id="addc-user" class="form-control bg-dark text-white" placeholder="1000 or username">
</div>
<div class="col-md-6">
<label class="form-label" for="addc-log-driver">Logging driver</label>
<select id="addc-log-driver" class="form-select bg-dark text-white">
<option value="">Default</option>
<option value="json-file">json-file</option>
<option value="local">local</option>
<option value="journald">journald</option>
<option value="syslog">syslog</option>
<option value="none">none</option>
</select>
</div>
<div class="col-12">
<label class="form-label" for="addc-health-cmd">Healthcheck command</label>
<input type="text" id="addc-health-cmd" class="form-control bg-dark text-white" placeholder="CMD-SHELL curl -f http://localhost/ || exit 1">
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-dark text-white" type="button" data-bs-toggle="collapse" data-bs-target="#addc-vols" aria-expanded="false">
Volumes
</button>
</h2>
<div id="addc-vols" class="accordion-collapse collapse" data-bs-parent="#addcAccordion">
<div class="accordion-body">
<div id="addc-volumes" class="mb-2"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="addc-add-volume">
<i class="fas fa-plus me-1"></i>Map additional volume
</button>
</div>
</div>
</div>
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-dark text-white" type="button" data-bs-toggle="collapse" data-bs-target="#addc-net" aria-expanded="false">
Network
</button>
</h2>
<div id="addc-net" class="accordion-collapse collapse" data-bs-parent="#addcAccordion">
<div class="accordion-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="addc-network-mode">Network mode</label>
<select id="addc-network-mode" class="form-select bg-dark text-white">
<option value="bridge">bridge</option>
<option value="host">host</option>
<option value="none">none</option>
<option value="container">container</option>
</select>
</div>
<div class="col-md-6" id="addc-custom-network-wrap">
<label class="form-label" for="addc-custom-network" id="addc-custom-network-label">Attach to network</label>
<input type="text" id="addc-custom-network" class="form-control bg-dark text-white" placeholder="optional network name">
<div class="form-text" id="addc-custom-network-hint">Named network to join after create (bridge mode)</div>
</div>
<div class="col-md-6">
<label class="form-label" for="addc-hostname">Hostname</label>
<input type="text" id="addc-hostname" class="form-control bg-dark text-white" placeholder="container-hostname">
</div>
<div class="col-md-6">
<label class="form-label" for="addc-domainname">Domain name</label>
<input type="text" id="addc-domainname" class="form-control bg-dark text-white" placeholder="example.com">
</div>
<div class="col-12">
<label class="form-label">DNS servers</label>
<div id="addc-dns" class="mb-2"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="addc-add-dns">
<i class="fas fa-plus me-1"></i>Add DNS server
</button>
</div>
<div class="col-12">
<label class="form-label">Hosts file entries</label>
<div id="addc-extra-hosts" class="mb-2"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="addc-add-extra-host">
<i class="fas fa-plus me-1"></i>Add hosts entry
</button>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-dark text-white" type="button" data-bs-toggle="collapse" data-bs-target="#addc-env-sec" aria-expanded="false">
Environment
</button>
</h2>
<div id="addc-env-sec" class="accordion-collapse collapse" data-bs-parent="#addcAccordion">
<div class="accordion-body">
<div id="addc-env" class="mb-2"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="addc-add-env">
<i class="fas fa-plus me-1"></i>Add environment variable
</button>
</div>
</div>
</div>
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-dark text-white" type="button" data-bs-toggle="collapse" data-bs-target="#addc-labels-sec" aria-expanded="false">
Labels
</button>
</h2>
<div id="addc-labels-sec" class="accordion-collapse collapse" data-bs-parent="#addcAccordion">
<div class="accordion-body">
<div id="addc-labels" class="mb-2"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="addc-add-label">
<i class="fas fa-plus me-1"></i>Add label
</button>
</div>
</div>
</div>
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-dark text-white" type="button" data-bs-toggle="collapse" data-bs-target="#addc-restart-sec" aria-expanded="false">
Restart policy
</button>
</h2>
<div id="addc-restart-sec" class="accordion-collapse collapse" data-bs-parent="#addcAccordion">
<div class="accordion-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="addc-restart-policy">Policy</label>
<select id="addc-restart-policy" class="form-select bg-dark text-white">
<option value="no">Never</option>
<option value="always">Always</option>
<option value="on-failure">On failure</option>
<option value="unless-stopped">Unless stopped</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label" for="addc-restart-max-retries">Max retries (on-failure)</label>
<input type="number" id="addc-restart-max-retries" class="form-control bg-dark text-white" min="0" placeholder="0">
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-dark text-white" type="button" data-bs-toggle="collapse" data-bs-target="#addc-runtime-sec" aria-expanded="false">
Runtime &amp; resources
</button>
</h2>
<div id="addc-runtime-sec" class="accordion-collapse collapse" data-bs-parent="#addcAccordion">
<div class="accordion-body">
<div class="row g-3">
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="addc-privileged">
<label class="form-check-label" for="addc-privileged">Privileged mode</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="addc-init">
<label class="form-check-label" for="addc-init">Init</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="addc-readonly-rootfs">
<label class="form-check-label" for="addc-readonly-rootfs">Read-only rootfs</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="addc-tty">
<label class="form-check-label" for="addc-tty">TTY</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="addc-stdin-open">
<label class="form-check-label" for="addc-stdin-open">Interactive (stdin)</label>
</div>
</div>
<div class="col-md-4">
<input type="checkbox" id="addc-detach" class="d-none" checked>
</div>
<div class="col-md-4">
<label class="form-label" for="addc-cpu-limit">CPU limit (cores)</label>
<input type="number" id="addc-cpu-limit" class="form-control bg-dark text-white" min="0" step="0.1" placeholder="Unlimited">
</div>
<div class="col-md-4">
<label class="form-label" for="addc-memory-limit">Memory limit (MB)</label>
<input type="number" id="addc-memory-limit" class="form-control bg-dark text-white" min="0" placeholder="Unlimited">
</div>
<div class="col-md-4">
<label class="form-label" for="addc-memory-reservation">Memory reservation (MB)</label>
<input type="number" id="addc-memory-reservation" class="form-control bg-dark text-white" min="0" placeholder="None">
</div>
<div class="col-md-4">
<label class="form-label" for="addc-shm-size">Shared memory (MB)</label>
<input type="number" id="addc-shm-size" class="form-control bg-dark text-white" min="0" placeholder="64">
</div>
<div class="col-12">
<label class="form-label">Capabilities (CapAdd)</label>
<div id="addc-capabilities" class="mb-2"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="addc-add-capability">
<i class="fas fa-plus me-1"></i>Add capability
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="addc-sticky-actions d-flex flex-wrap gap-2 align-items-center mb-4">
<button type="button" class="btn btn-primary" id="addc-deploy-btn-bottom" data-min-role="operator" onclick="document.getElementById('addc-deploy-btn')?.click()">
<i class="fas fa-rocket me-2"></i>Deploy the container
</button>
<button type="button" class="btn btn-outline-secondary" onclick="navigateToView('containers')">Cancel</button>
</div>
</form>
</div>
</div>
<!-- Images View -->
<div id="images-view" class="view hidden">
<div class="container-fluid">