This commit is contained in:
retoor 2025-06-08 18:49:47 +02:00
parent 987bd3a1c7
commit 92573ebeb4
5 changed files with 61 additions and 22 deletions

View File

@ -176,7 +176,9 @@ class ChatInputComponent extends HTMLElement {
}); });
this.appendChild(this.uploadButton); this.appendChild(this.uploadButton);
this.textarea.addEventListener("blur", () => {
this.updateFromInput("");
});
this.textarea.addEventListener("keyup", (e) => { this.textarea.addEventListener("keyup", (e) => {
if (e.key === "Enter" && !e.shiftKey) { if (e.key === "Enter" && !e.shiftKey) {

View File

@ -17,15 +17,20 @@ export class Container extends EventHandler{
this._container = el this._container = el
this.terminal.open(this._container) this.terminal.open(this._container)
this.terminal.onData(data => this.ws.send(new TextEncoder().encode(data)));
this.terminal.onData(data => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
}
});
} }
this._fitAddon.fit();
this.refresh() this.refresh()
this.terminal.focus()
} }
refresh(){ refresh(){
this._fitAddon.fit(); //this._fitAddon.fit();
this.terminal.write("\x0C"); this.ws.send("\x0C");
} }
toggle(){ toggle(){
this._container.classList.toggle("hidden") this._container.classList.toggle("hidden")
@ -34,7 +39,10 @@ export class Container extends EventHandler{
constructor(channelUid,log){ constructor(channelUid,log){
super() super()
this.terminal = new Terminal({ cursorBlink: true }); this.terminal = new Terminal({ cursorBlink: true ,theme: {
background: 'rgba(0, 0, 0, 0)', // Fully transparent
}
});
this._fitAddon = new FitAddon.FitAddon(); this._fitAddon = new FitAddon.FitAddon();
this.terminal.loadAddon(this._fitAddon); this.terminal.loadAddon(this._fitAddon);
window.addEventListener("resize", () => this._fitAddon.fit()); window.addEventListener("resize", () => this._fitAddon.fit());

View File

@ -3,6 +3,8 @@ import json
import yaml import yaml
import asyncio import asyncio
import subprocess import subprocess
import pty
import os
class ComposeFileManager: class ComposeFileManager:
def __init__(self, compose_path="docker-compose.yml",event_handler=None): def __init__(self, compose_path="docker-compose.yml",event_handler=None):
@ -31,17 +33,19 @@ class ComposeFileManager:
return False return False
proc = self.running_instances.get(container_name) proc = self.running_instances.get(container_name)
if not proc: if not proc:
return False return False
async def reader(event_handler,stream): async def reader(event_handler,stream):
loop = asyncio.get_event_loop()
while True: while True:
line = await stream.read(1024) line = await loop.run_in_executor(None,os.read,stream,1024)
print("XXX",line) print("XXX",line)
if not line: if not line:
break break
await event_handler(container_name,"stdout",line) await event_handler(container_name,"stdout",line)
await self.stop(container_name) await self.stop(container_name)
asyncio.create_task(reader(self.event_handler,proc.stdout)) asyncio.create_task(reader(self.event_handler,proc['master']))
asyncio.create_task(reader(self.event_handler,proc.stderr))
def create_instance( def create_instance(
@ -123,7 +127,7 @@ class ComposeFileManager:
if not proc: if not proc:
return False return False
try: try:
proc.stdin.write(data.encode()) os.write(proc['master'], data.encode())
return True return True
except Exception as ex: except Exception as ex:
print(ex) print(ex)
@ -178,13 +182,16 @@ class ComposeFileManager:
if proc.returncode != 0: if proc.returncode != 0:
print(f"Failed to start {name}: {stderr.decode(errors='ignore')}") print(f"Failed to start {name}: {stderr.decode(errors='ignore')}")
return False return False
master, slave = pty.openpty()
proc = await asyncio.create_subprocess_exec( proc = await asyncio.create_subprocess_exec(
"docker", "compose", "-f", self.compose_path, "exec", name, "/bin/bash", "docker", "compose", "-f", self.compose_path, "exec", name, "/bin/bash",
stdin=asyncio.subprocess.PIPE, stdin=slave,
stdout=asyncio.subprocess.PIPE, stdout=slave,
stderr=asyncio.subprocess.PIPE, stderr=slave,
) )
proc = {'proc':proc,'master':master,'slave':slave}
# stdin,stderr = await proc.communicate() # stdin,stderr = await proc.communicate()
self.running_instances[name] = proc self.running_instances[name] = proc
#if stdout: #if stdout:

View File

@ -54,7 +54,28 @@
<script type="module"> <script type="module">
import { app } from "/app.js"; import { app } from "/app.js";
import { Container } from "/container.js"; import { Container } from "/container.js";
{% if channel %} let prevKey = null;
document.addEventListener("keydown", () => {
if(prevKey == "Escape"){
document.querySelector("chat-input").querySelector("textarea").value = "";
}
if(prevKey == "Escape" && event.key == "t"){
app.starField.shuffleAll(5000)
}
prevKey = event.key
if(event.key == "," && event.ctrlKey){
event.preventDefault();
let textAreas = document.querySelectorAll("textarea")
textAreas.forEach(textArea => {
if(document.activeElement != textArea)
setTimeout(() => textArea.focus(), 300)
})
}
})
{% if channel %}
app.channelUid = '{{ channel.uid.value }}' app.channelUid = '{{ channel.uid.value }}'
window.getContainer = function(){ window.getContainer = function(){

View File

@ -56,12 +56,13 @@ chatInputField.autoCompletions = {
"/help": showHelp, "/help": showHelp,
"/container": async() =>{ "/container": async() =>{
if(container == null){ if(container == null){
container = await window.getContainer() window.c = await window.getContainer()
const terminal = document.querySelector("#terminal") await window.c.start()
terminal.classList.toggle("hidden") window.t = document.querySelector("#terminal")
container.render(terminal) window.t.classList.toggle("hidden")
window.c.render(window.t)
} }
containerDialog.openWithStatus() //containerDialog.openWithStatus()
} }
}; };