Docker: add a Compose stack manager (Containers | Stacks toggle): list stacks in a stacks folder (default /opt/stacks) plus projects found via compose ls, create/edit compose.yaml and .env in an editor (validated with compose config), deploy/stop/restart/down/pull/logs/delete in terminal tabs, clone stacks from Git and git pull + redeploy, app templates in Portainer format (default Lissy93/portainer-templates: container templates are converted to compose, stack templates loaded from GitHub), "Set up folder" makes the stacks folder writable for the SSH user
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -336,6 +336,29 @@ kbd { background: var(--card); border: 1px solid var(--border); border-bottom-wi
|
||||
|
||||
/* Firewall */
|
||||
.seg.sm button { padding: 4px 10px; font-size: 12px; }
|
||||
.session.docker .sbar .seg { margin: 0 6px 0 0; flex: none; }
|
||||
.docker-table .dot.none { background: transparent; border: 1px solid var(--faint); }
|
||||
.docker-table .badge, .tpl-it .badge { font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: 6px; background: var(--icon-bg); color: var(--muted); margin-left: 4px; vertical-align: middle; }
|
||||
.stack-bar { display: flex; align-items: center; gap: 6px; padding: 8px 10px; border-bottom: 1px solid var(--border); flex-wrap: wrap; position: sticky; top: 0; background: var(--bg); z-index: 2; }
|
||||
.stack-bar .muted { color: var(--muted); font-size: 12px; }
|
||||
.stack-bar + .docker-table th { top: 45px; }
|
||||
.stack-editor { display: flex; flex-direction: column; height: 100%; }
|
||||
.stack-editor .se-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
|
||||
.stack-editor .se-name { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; color: var(--text); padding: 5px 8px; width: 200px; font: inherit; }
|
||||
.stack-editor .se-note { padding: 8px 12px; color: var(--muted); font-size: 12px; border-bottom: 1px solid var(--border); max-height: 80px; overflow: auto; }
|
||||
.stack-editor .se-grid { flex: 1; display: grid; grid-template-columns: 2fr 1fr; gap: 10px; padding: 10px; min-height: 0; }
|
||||
.stack-editor .se-col { display: flex; flex-direction: column; min-height: 0; gap: 6px; }
|
||||
.stack-editor .se-col label { font-size: 12px; color: var(--muted); font-weight: 600; }
|
||||
.stack-editor textarea { flex: 1; resize: none; background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 8px; padding: 10px; font-size: 13px; line-height: 1.45; tab-size: 2; white-space: pre; min-height: 200px; }
|
||||
@media (max-width: 800px) { .stack-editor .se-grid { grid-template-columns: 1fr; } }
|
||||
.modal.wide { width: min(760px, 94vw); max-width: none; }
|
||||
.tpl-top { display: flex; gap: 8px; margin-bottom: 8px; }
|
||||
.tpl-top .search { margin: 0; }
|
||||
.tpl-top select { background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 8px; padding: 0 8px; }
|
||||
.tpl-list { max-height: 55vh; overflow: auto; display: flex; flex-direction: column; gap: 6px; }
|
||||
.tpl-it { background: var(--card); border-radius: 8px; padding: 9px 11px; cursor: pointer; }
|
||||
.tpl-it:hover { background: var(--card-hover); }
|
||||
.tpl-it .d { color: var(--muted); font-size: 12px; margin-top: 3px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.fw-head { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
|
||||
.fw-def { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12px; margin-left: 8px; }
|
||||
.fw-def select { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: 4px 8px; color: var(--text); }
|
||||
|
||||
Reference in New Issue
Block a user