Unify separation tools and add exclusive control mode

This commit is contained in:
Mikei386 committed 2026-10-01 16:56:13 +02:00
1 parent 088f5f6f91
commit bd5aea7656
13 files changed
+81 -28

No files matched your search

+8 -1
View File
@@ -1,10 +1,17 @@
window.DockerUI=(()=>{
const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
const apps={
'athena-ladypoly':{title:'LadyPoly YuE2',description:'Weboberfläche für Decks Musiklaufzeit.',port:8127,hint:'In der Steuerung Musik starten. Deck-Verbindung in LadyPoly einrichten.'},
'athena-separator-web':{title:'Athena Separator Web',description:'Gesang oder Instrumente herauslösen; Verarbeitung durch Decks native Audio-Separator-Laufzeit.',port:8128,hint:'In der Steuerung Audio-Trennung starten. Modelle unter Audio-Trennung einrichten.'},
'ltx-deskweb':{title:'LTX DeskWEB',description:'LTX-Webstudio für Videoerzeugung über Decks originale LTX-Laufzeit.',port:8118,hint:'Videoprofil freigeben und in der Steuerung Video starten.'},
'athena-swarm-ui':{title:'SwarmUI',description:'API By URL · Oberfläche für Decks ComfyUI-Laufzeit.',port:8125,hint:'In der Steuerung Video mit ComfyUI starten.'}
};
function appInfo(c){const a=apps[c.name];return a?`<p>${esc(a.description)}</p><a class="link" href="${esc(location.protocol+'//'+location.hostname+':'+a.port+'/')}" target="_blank" rel="noopener">${esc(a.title)} öffnen →</a><p class="small">${esc(a.hint)} SSH-Tunnel: Port ${a.port}.</p>`:'';}
async function api(action='',data){const r=await fetch('/api/v1/docker'+action,data?{method:'POST',headers:{'Content-Type':'application/json','X-Athena-Deck':'1'},body:JSON.stringify(data)}:{});if(r.status===401){location.reload();throw Error('Bitte erneut anmelden.');}const value=await r.json();if(!r.ok)throw Error(value.error||'Docker-Anfrage fehlgeschlagen');return value;}
function html(services=false){return `<div class="kicker">${services?'ANWENDUNGEN':'EINSTELLUNGEN / LAUFZEITEN'}</div><h1>${services?'Weitere Dienste':'Docker'}</h1><p>${services?'Zusätzliche Oberflächen werden getrennt von Modellen und Laufzeiten verwaltet. Hier erscheinen ausschließlich ausdrücklich für Deck markierte Anwendungscontainer.':'Optionale Umgebung für zusätzliche Studios. Native Modelllaufzeiten bleiben unabhängig davon.'}</p><section id="docker-panel"></section><p id="docker-message" role="status"></p>`;}
function bind(services=false){const panel=document.querySelector('#docker-panel'),message=document.querySelector('#docker-message');let signature='',pending=false,timer;
async function refresh(){clearTimeout(timer);try{if(pending)return;const s=await api();if(!panel.isConnected)return;const next=JSON.stringify(s);if(signature!==next){signature=next;const running=s.job?.state==='running';
if(services){panel.innerHTML=`<section class="card"><h2>Explizite Zuordnung</h2><p>Beide Container-Labels müssen gesetzt sein:</p><pre><code>io.athena-deck.managed=true\nio.athena-deck.role=application</code></pre><p class="small">Keine automatische Übernahme vorhandener Container. Labels werden beim Erstellen in Docker Compose gesetzt. Starten und Stoppen betrifft nur markierte Container. Löschen entfernt den Container einschließlich seiner beschreibbaren Schicht; Images und Volumes bleiben erhalten.</p><a class="link" href="#docker-runtime">Docker-Verbindung prüfen →</a></section>${!s.helper_available||!s.reachable?'<section class="empty"><h2>Docker nicht verbunden</h2><p>'+esc(s.message)+'</p></section>':s.services.length?'<div class="grid">'+s.services.map(c=>`<section class="card"><span class="pill">DOCKER · DECK-ANWENDUNG</span><h2>${esc(c.name)}</h2><p>${esc(c.image)}</p><p><strong>${esc(c.state)}</strong> · ${esc(c.status)}</p>${c.name==='athena-ladypoly'?`<p>LadyPoly YuE2 · Oberfläche für Decks Musiklaufzeit</p><a class="link" href="${esc(location.protocol+'//'+location.hostname+':8127/')}" target="_blank" rel="noopener">LadyPoly öffnen →</a><p class="small">Zuerst Deck-Verbindung einrichten und in der Übersicht Musik aktivieren. SSH-Tunnel: Port 8127.</p>`:''}${c.name==='athena-swarm-ui'?`<p>API By URL · Deck steuert die Video-Laufzeit</p><a class="link" href="${esc(location.protocol+'//'+location.hostname+':8125/')}" target="_blank" rel="noopener">SwarmUI öffnen →</a><p class="small">In Deck zuerst Video aktivieren. Zugriff über den SSH-Tunnel auf Port 8125.</p>`:''}<div class="card-actions"><button data-container-action="start" data-container-id="${esc(c.id)}" ${c.state==='running'?'disabled':''}>Starten</button><button class="secondary" data-container-action="stop" data-container-id="${esc(c.id)}" ${c.state!=='running'?'disabled':''}>Stoppen</button><button class="secondary danger" data-container-action="delete" data-container-id="${esc(c.id)}" ${!['exited','created','dead'].includes(c.state)?'disabled':''}>Löschen</button></div></section>`).join('')+'</div>' :'<section class="empty"><h2>Noch keine Deck-Anwendungen</h2><p>Docker ist erreichbar. Kein Container trägt beide erforderlichen Labels. Bestehende Router-, WireGuard- und andere Container bleiben ausgeblendet.</p></section>'}`;}
if(services){panel.innerHTML=`<section class="card"><h2>Explizite Zuordnung</h2><p>Beide Container-Labels müssen gesetzt sein:</p><pre><code>io.athena-deck.managed=true\nio.athena-deck.role=application</code></pre><p class="small">Keine automatische Übernahme vorhandener Container. Labels werden beim Erstellen in Docker Compose gesetzt. Starten und Stoppen betrifft nur markierte Container. Löschen entfernt den Container einschließlich seiner beschreibbaren Schicht; Images und Volumes bleiben erhalten.</p><a class="link" href="#docker-runtime">Docker-Verbindung prüfen →</a></section>${!s.helper_available||!s.reachable?'<section class="empty"><h2>Docker nicht verbunden</h2><p>'+esc(s.message)+'</p></section>':s.services.length?'<div class="grid">'+s.services.map(c=>`<section class="card"><span class="pill">DOCKER · DECK-ANWENDUNG</span><h2>${esc(c.name)}</h2><p>${esc(c.image)}</p><p><strong>${esc(c.state)}</strong> · ${esc(c.status)}</p>${appInfo(c)}<div class="card-actions"><button data-container-action="start" data-container-id="${esc(c.id)}" ${c.state==='running'?'disabled':''}>Starten</button><button class="secondary" data-container-action="stop" data-container-id="${esc(c.id)}" ${c.state!=='running'?'disabled':''}>Stoppen</button><button class="secondary danger" data-container-action="delete" data-container-id="${esc(c.id)}" ${!['exited','created','dead'].includes(c.state)?'disabled':''}>Löschen</button></div></section>`).join('')+'</div>' :'<section class="empty"><h2>Noch keine Deck-Anwendungen</h2><p>Docker ist erreichbar. Kein Container trägt beide erforderlichen Labels. Bestehende Router-, WireGuard- und andere Container bleiben ausgeblendet.</p></section>'}`;}
else {panel.innerHTML=`<section class="card"><span class="pill">${s.installed?'INSTALLIERT':s.installed===false?'NICHT INSTALLIERT':'NICHT ERMITTELBAR'}</span><h2>Docker Engine ${esc(s.version||'')}</h2><p>${s.reachable?'Daemon erreichbar · Verbindung über begrenzten Systemhelfer':s.helper_available?'Systemhelfer erreichbar · Docker-Daemon nicht erreichbar':'Systemhelfer nicht verbunden'}</p><p>${esc(s.message)}</p>${s.job?`<p role="status">${esc(s.job.state)} · ${esc(s.job.phase)}</p>`:''}${!s.installed&&s.install_supported&&!running?'<label><input type="checkbox" id="docker-install-ack"> Docker Engine, Compose und Buildx auf diesem Server installieren. Docker richtet einen Dienst und Netzwerk-/Firewallregeln ein.</label><p><button id="docker-install" disabled>Docker installieren</button></p>':`<button disabled>${running?'Installation läuft …':s.installed?'Docker bereits vorhanden':'Installation hier nicht verfügbar'}</button>`}<p class="small">Keine automatische Aktualisierung vorhandener Docker-Installationen. NVIDIA Container Toolkit und Treiber sind separate Voraussetzungen für GPU-Container. Die Paketinstallation wird nicht mitten im Vorgang abgebrochen.</p><a class="link" href="#services">Weitere Dienste öffnen →</a></section>`;
const button=panel.querySelector('#docker-install'),ack=panel.querySelector('#docker-install-ack');if(button){ack.onchange=()=>button.disabled=pending||!ack.checked;button.onclick=async()=>{pending=true;button.disabled=true;try{await api('/install',{confirm:true});message.textContent='Docker-Erstinstallation gestartet.';}catch(error){message.textContent=error.message;}finally{pending=false;signature='';}};}
}