window.DockerUI=(()=>{ const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[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?`

${esc(a.description)}

${esc(a.title)} öffnen →

${esc(a.hint)} SSH-Tunnel: Port ${a.port}.

`:'';} 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 `
${services?'ANWENDUNGEN':'EINSTELLUNGEN / LAUFZEITEN'}

${services?'Weitere Dienste':'Docker'}

${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.'}

`;} 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=`

Explizite Zuordnung

Beide Container-Labels müssen gesetzt sein:

io.athena-deck.managed=true\nio.athena-deck.role=application

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.

Docker-Verbindung prüfen →
${!s.helper_available||!s.reachable?'

Docker nicht verbunden

'+esc(s.message)+'

':s.services.length?'
'+s.services.map(c=>`
DOCKER · DECK-ANWENDUNG

${esc(c.name)}

${esc(c.image)}

${esc(c.state)} · ${esc(c.status)}

${appInfo(c)}
`).join('')+'
' :'

Noch keine Deck-Anwendungen

Docker ist erreichbar. Kein Container trägt beide erforderlichen Labels. Bestehende Router-, WireGuard- und andere Container bleiben ausgeblendet.

'}`;} else {panel.innerHTML=`
${s.installed?'INSTALLIERT':s.installed===false?'NICHT INSTALLIERT':'NICHT ERMITTELBAR'}

Docker Engine ${esc(s.version||'')}

${s.reachable?'Daemon erreichbar · Verbindung über begrenzten Systemhelfer':s.helper_available?'Systemhelfer erreichbar · Docker-Daemon nicht erreichbar':'Systemhelfer nicht verbunden'}

${esc(s.message)}

${s.job?`

${esc(s.job.state)} · ${esc(s.job.phase)}

`:''}${!s.installed&&s.install_supported&&!running?'

':``}

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.

Weitere Dienste öffnen →
`; 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='';}};} } } if(services)panel.querySelectorAll('[data-container-action]').forEach(b=>b.onclick=async()=>{ const action=b.dataset.containerAction,id=b.dataset.containerId,c=s.services.find(c=>c.id===id); if(pending||!c)return; if(action==='delete'&&!confirm(`Container „${c.name}“ endgültig löschen? Die beschreibbare Container-Schicht geht verloren. Images und Volumes bleiben erhalten.`))return; pending=true;panel.querySelectorAll('button').forEach(x=>x.disabled=true);message.textContent=action==='stop'?'Container wird gestoppt (bis zu 30 Sekunden) …':action==='start'?'Container wird gestartet …':'Container wird gelöscht …'; try{await api('/'+action,{id,...(action==='delete'?{confirm:true}:{})});message.textContent=action==='delete'?'Container gelöscht. Images und Volumes bleiben erhalten.':action==='start'?'Container gestartet.':'Container gestoppt.';} catch(error){message.textContent=error.message;} finally{pending=false;signature='';if(panel.isConnected)refresh();} }); }catch(error){if(panel.isConnected){message.textContent=error.message;signature='';}}finally{if(panel.isConnected)timer=setTimeout(refresh,5000);}} refresh(); } return {html,bind}; })();