mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-12-14 16:16:21 +00:00
Update script-terminal-modal.tsx
This commit is contained in:
@@ -58,6 +58,8 @@ export function ScriptTerminalModal({
|
|||||||
const [currentInteraction, setCurrentInteraction] = useState<WebInteraction | null>(null)
|
const [currentInteraction, setCurrentInteraction] = useState<WebInteraction | null>(null)
|
||||||
const [interactionInput, setInteractionInput] = useState("")
|
const [interactionInput, setInteractionInput] = useState("")
|
||||||
const checkConnectionInterval = useRef<NodeJS.Timeout | null>(null)
|
const checkConnectionInterval = useRef<NodeJS.Timeout | null>(null)
|
||||||
|
const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||||
|
const reconnectAttemptsRef = useRef(0)
|
||||||
const [isMobile, setIsMobile] = useState(false)
|
const [isMobile, setIsMobile] = useState(false)
|
||||||
const [isTablet, setIsTablet] = useState(false)
|
const [isTablet, setIsTablet] = useState(false)
|
||||||
|
|
||||||
@@ -69,11 +71,103 @@ export function ScriptTerminalModal({
|
|||||||
const resizeBarRef = useRef<HTMLDivElement>(null)
|
const resizeBarRef = useRef<HTMLDivElement>(null)
|
||||||
const modalHeightRef = useRef(600) // Ref para mantener el valor actualizado
|
const modalHeightRef = useRef(600) // Ref para mantener el valor actualizado
|
||||||
|
|
||||||
// Debug visual para tablets
|
|
||||||
const [debugInfo, setDebugInfo] = useState<string[]>([])
|
|
||||||
|
|
||||||
const terminalContainerRef = useRef<HTMLDivElement>(null)
|
const terminalContainerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
const attemptReconnect = useCallback(() => {
|
||||||
|
if (!isOpen || isComplete || reconnectAttemptsRef.current >= 3) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnectAttemptsRef.current++
|
||||||
|
setConnectionStatus("connecting")
|
||||||
|
|
||||||
|
if (reconnectTimeoutRef.current) {
|
||||||
|
clearTimeout(reconnectTimeoutRef.current)
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnectTimeoutRef.current = setTimeout(() => {
|
||||||
|
if (wsRef.current?.readyState !== WebSocket.OPEN && termRef.current) {
|
||||||
|
// Cerrar conexión anterior si existe
|
||||||
|
if (wsRef.current) {
|
||||||
|
wsRef.current.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear nueva conexión
|
||||||
|
const wsUrl = getScriptWebSocketUrl(sessionIdRef.current)
|
||||||
|
const ws = new WebSocket(wsUrl)
|
||||||
|
wsRef.current = ws
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
setConnectionStatus("online")
|
||||||
|
reconnectAttemptsRef.current = 0
|
||||||
|
|
||||||
|
// Reiniciar el script
|
||||||
|
const initMessage = {
|
||||||
|
script_path: scriptPath,
|
||||||
|
params: {
|
||||||
|
EXECUTION_MODE: "web",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ws.send(JSON.stringify(initMessage))
|
||||||
|
|
||||||
|
// Redimensionar terminal
|
||||||
|
setTimeout(() => {
|
||||||
|
if (fitAddonRef.current && termRef.current && ws.readyState === WebSocket.OPEN) {
|
||||||
|
const cols = termRef.current.cols
|
||||||
|
const rows = termRef.current.rows
|
||||||
|
ws.send(JSON.stringify({ type: "resize", cols, rows }))
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const msg = JSON.parse(event.data)
|
||||||
|
if (msg.type === "web_interaction" && msg.interaction) {
|
||||||
|
setIsWaitingNextInteraction(false)
|
||||||
|
if (waitingTimeoutRef.current) {
|
||||||
|
clearTimeout(waitingTimeoutRef.current)
|
||||||
|
}
|
||||||
|
setCurrentInteraction({
|
||||||
|
type: msg.interaction.type,
|
||||||
|
id: msg.interaction.id,
|
||||||
|
title: msg.interaction.title || "",
|
||||||
|
message: msg.interaction.message || "",
|
||||||
|
options: msg.interaction.options,
|
||||||
|
default: msg.interaction.default,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (msg.type === "error") {
|
||||||
|
termRef.current?.writeln(`\x1b[31m${msg.message}\x1b[0m`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
termRef.current?.write(event.data)
|
||||||
|
setIsWaitingNextInteraction(false)
|
||||||
|
if (waitingTimeoutRef.current) {
|
||||||
|
clearTimeout(waitingTimeoutRef.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onerror = () => {
|
||||||
|
setConnectionStatus("offline")
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onclose = (event) => {
|
||||||
|
setConnectionStatus("offline")
|
||||||
|
if (!isComplete && reconnectAttemptsRef.current < 3) {
|
||||||
|
// Intentar reconectar después de 2 segundos
|
||||||
|
reconnectTimeoutRef.current = setTimeout(attemptReconnect, 2000)
|
||||||
|
} else {
|
||||||
|
setIsComplete(true)
|
||||||
|
setExitCode(event.code === 1000 ? 0 : 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}, [isOpen, isComplete, scriptPath])
|
||||||
|
|
||||||
const sendKey = useCallback((key: string) => {
|
const sendKey = useCallback((key: string) => {
|
||||||
if (!termRef.current) return
|
if (!termRef.current) return
|
||||||
|
|
||||||
@@ -293,6 +387,9 @@ export function ScriptTerminalModal({
|
|||||||
if (waitingTimeoutRef.current) {
|
if (waitingTimeoutRef.current) {
|
||||||
clearTimeout(waitingTimeoutRef.current)
|
clearTimeout(waitingTimeoutRef.current)
|
||||||
}
|
}
|
||||||
|
if (reconnectTimeoutRef.current) {
|
||||||
|
clearTimeout(reconnectTimeoutRef.current)
|
||||||
|
}
|
||||||
if (wsRef.current) {
|
if (wsRef.current) {
|
||||||
wsRef.current.close()
|
wsRef.current.close()
|
||||||
wsRef.current = null
|
wsRef.current = null
|
||||||
@@ -303,6 +400,7 @@ export function ScriptTerminalModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
sessionIdRef.current = Math.random().toString(36).substring(2, 8)
|
sessionIdRef.current = Math.random().toString(36).substring(2, 8)
|
||||||
|
reconnectAttemptsRef.current = 0
|
||||||
setIsComplete(false)
|
setIsComplete(false)
|
||||||
setExitCode(null)
|
setExitCode(null)
|
||||||
setInteractionInput("")
|
setInteractionInput("")
|
||||||
@@ -326,10 +424,32 @@ export function ScriptTerminalModal({
|
|||||||
const handleResize = () => updateDeviceType()
|
const handleResize = () => updateDeviceType()
|
||||||
window.addEventListener("resize", handleResize)
|
window.addEventListener("resize", handleResize)
|
||||||
|
|
||||||
|
// Detectar cuando la app vuelve a estar visible (desbloqueo de pantalla)
|
||||||
|
const handleVisibilityChange = () => {
|
||||||
|
if (!document.hidden && isOpen) {
|
||||||
|
// La pantalla se desbloqueó, verificar conexión
|
||||||
|
if (wsRef.current?.readyState !== WebSocket.OPEN && !isComplete) {
|
||||||
|
attemptReconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar cuando la app vuelve desde background
|
||||||
|
const handleFocus = () => {
|
||||||
|
if (isOpen && wsRef.current?.readyState !== WebSocket.OPEN && !isComplete) {
|
||||||
|
attemptReconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("visibilitychange", handleVisibilityChange)
|
||||||
|
window.addEventListener("focus", handleFocus)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("resize", handleResize)
|
window.removeEventListener("resize", handleResize)
|
||||||
|
document.removeEventListener("visibilitychange", handleVisibilityChange)
|
||||||
|
window.removeEventListener("focus", handleFocus)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [isOpen, isComplete, attemptReconnect])
|
||||||
|
|
||||||
const getScriptWebSocketUrl = (sid: string): string => {
|
const getScriptWebSocketUrl = (sid: string): string => {
|
||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
@@ -394,44 +514,38 @@ export function ScriptTerminalModal({
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
const debugMsg = `[${new Date().toLocaleTimeString()}] Resize start - Type: ${e.type}, isMobile: ${isMobile}, isTablet: ${isTablet}`
|
|
||||||
console.log(debugMsg)
|
|
||||||
setDebugInfo(prev => [...prev.slice(-4), debugMsg])
|
|
||||||
|
|
||||||
setIsResizing(true)
|
setIsResizing(true)
|
||||||
|
|
||||||
// Detectar si es touch o mouse
|
|
||||||
const clientY = "touches" in e ? e.touches[0].clientY : e.clientY
|
const clientY = "touches" in e ? e.touches[0].clientY : e.clientY
|
||||||
const startY = clientY
|
const startY = clientY
|
||||||
const startHeight = modalHeight
|
const startHeight = modalHeight
|
||||||
|
|
||||||
const debugMsg2 = `Start Y: ${startY}, Start height: ${startHeight}`
|
|
||||||
console.log(debugMsg2)
|
|
||||||
setDebugInfo(prev => [...prev.slice(-4), debugMsg2])
|
|
||||||
|
|
||||||
let moveCount = 0
|
|
||||||
|
|
||||||
const handleMove = (moveEvent: MouseEvent | TouchEvent) => {
|
const handleMove = (moveEvent: MouseEvent | TouchEvent) => {
|
||||||
moveEvent.preventDefault()
|
|
||||||
moveEvent.stopPropagation()
|
|
||||||
|
|
||||||
const currentY = "touches" in moveEvent ? moveEvent.touches[0].clientY : moveEvent.clientY
|
const currentY = "touches" in moveEvent ? moveEvent.touches[0].clientY : moveEvent.clientY
|
||||||
const deltaY = currentY - startY
|
const deltaY = currentY - startY
|
||||||
const newHeight = Math.max(300, Math.min(window.innerHeight - 100, startHeight + deltaY))
|
const newHeight = Math.max(300, Math.min(window.innerHeight - 50, startHeight + deltaY))
|
||||||
|
|
||||||
moveCount++
|
// Actualizar directamente sin requestAnimationFrame para mayor fluidez
|
||||||
if (moveCount % 5 === 0) {
|
|
||||||
console.log(`Move #${moveCount} - currentY: ${currentY}, deltaY: ${deltaY}, newHeight: ${newHeight}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actualizar tanto el state como el ref
|
|
||||||
modalHeightRef.current = newHeight
|
modalHeightRef.current = newHeight
|
||||||
setModalHeight(newHeight)
|
setModalHeight(newHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEnd = () => {
|
||||||
|
const finalHeight = modalHeightRef.current
|
||||||
|
setIsResizing(false)
|
||||||
|
|
||||||
|
document.removeEventListener("mousemove", handleMove as any)
|
||||||
|
document.removeEventListener("mouseup", handleEnd)
|
||||||
|
document.removeEventListener("touchmove", handleMove as any)
|
||||||
|
document.removeEventListener("touchend", handleEnd)
|
||||||
|
document.removeEventListener("touchcancel", handleEnd)
|
||||||
|
|
||||||
|
localStorage.setItem("scriptModalHeight", finalHeight.toString())
|
||||||
|
|
||||||
|
// Ajustar terminal al final del resize
|
||||||
if (fitAddonRef.current && termRef.current && wsRef.current?.readyState === WebSocket.OPEN) {
|
if (fitAddonRef.current && termRef.current && wsRef.current?.readyState === WebSocket.OPEN) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (fitAddonRef.current && termRef.current) {
|
fitAddonRef.current?.fit()
|
||||||
fitAddonRef.current.fit()
|
|
||||||
wsRef.current?.send(
|
wsRef.current?.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: "resize",
|
type: "resize",
|
||||||
@@ -439,35 +553,15 @@ export function ScriptTerminalModal({
|
|||||||
rows: termRef.current.rows,
|
rows: termRef.current.rows,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}, 100)
|
||||||
}, 10)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEnd = () => {
|
document.addEventListener("mousemove", handleMove as any)
|
||||||
// Usar el ref que tiene el valor actualizado
|
document.addEventListener("mouseup", handleEnd)
|
||||||
const finalHeight = modalHeightRef.current
|
document.addEventListener("touchmove", handleMove as any, { passive: false })
|
||||||
const debugMsg3 = `Resize end - Final height: ${finalHeight}, Total moves: ${moveCount}`
|
document.addEventListener("touchend", handleEnd)
|
||||||
console.log(debugMsg3)
|
document.addEventListener("touchcancel", handleEnd)
|
||||||
setDebugInfo(prev => [...prev.slice(-4), debugMsg3])
|
|
||||||
|
|
||||||
setIsResizing(false)
|
|
||||||
|
|
||||||
document.removeEventListener("mousemove", handleMove as any, false)
|
|
||||||
document.removeEventListener("mouseup", handleEnd, false)
|
|
||||||
document.removeEventListener("touchmove", handleMove as any, false)
|
|
||||||
document.removeEventListener("touchend", handleEnd, false)
|
|
||||||
document.removeEventListener("touchcancel", handleEnd, false)
|
|
||||||
|
|
||||||
// Guardar usando el valor del ref
|
|
||||||
localStorage.setItem("scriptModalHeight", finalHeight.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("mousemove", handleMove as any, false)
|
|
||||||
document.addEventListener("mouseup", handleEnd, false)
|
|
||||||
document.addEventListener("touchmove", handleMove as any, { passive: false, capture: false })
|
|
||||||
document.addEventListener("touchend", handleEnd, false)
|
|
||||||
document.addEventListener("touchcancel", handleEnd, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendCommand = (command: string) => {
|
const sendCommand = (command: string) => {
|
||||||
@@ -498,15 +592,6 @@ export function ScriptTerminalModal({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Debug panel - solo visible en tablets */}
|
|
||||||
{isTablet && debugInfo.length > 0 && (
|
|
||||||
<div className="bg-yellow-900/50 border-b border-yellow-700 p-2 text-xs font-mono text-yellow-200 max-h-20 overflow-y-auto">
|
|
||||||
{debugInfo.map((info, i) => (
|
|
||||||
<div key={i}>{info}</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="overflow-hidden relative flex-1">
|
<div className="overflow-hidden relative flex-1">
|
||||||
<div ref={terminalContainerRef} className="w-full h-full" />
|
<div ref={terminalContainerRef} className="w-full h-full" />
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user