diff --git a/AppImage/components/script-terminal-modal.tsx b/AppImage/components/script-terminal-modal.tsx index 1fc312e..808b2f1 100644 --- a/AppImage/components/script-terminal-modal.tsx +++ b/AppImage/components/script-terminal-modal.tsx @@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { X, CheckCircle2, XCircle, Loader2 } from "lucide-react" -import { TerminalPanel, type TerminalPanelHandle } from "./terminal-panel" +import { TerminalPanel } from "./terminal-panel" import { API_PORT } from "@/lib/api-config" interface WebInteraction { @@ -42,36 +42,16 @@ export function ScriptTerminalModal({ const [exitCode, setExitCode] = useState(null) const [currentInteraction, setCurrentInteraction] = useState(null) const [interactionInput, setInteractionInput] = useState("") - const terminalRef = useRef(null) - - useEffect(() => { - console.log("[v0] currentInteraction changed:", currentInteraction) - if (currentInteraction) { - console.log("[v0] Interaction opened, type:", currentInteraction.type, "id:", currentInteraction.id) - } else { - console.log("[v0] Interaction closed/cleared") - console.trace("[v0] Stack trace for currentInteraction = null") - } - }, [currentInteraction]) + const wsRef = useRef(null) useEffect(() => { if (open) { - console.log("[v0] ScriptTerminalModal opened with:", { - scriptPath, - scriptName, - params, - sessionId, - }) - // Reset state only when modal opens setIsComplete(false) setExitCode(null) setInteractionInput("") - // Don't clear currentInteraction here - it causes issues - } else { - // Clear interaction when modal closes setCurrentInteraction(null) } - }, [open]) // Only depend on 'open' to avoid unnecessary re-runs + }, [open]) const getScriptWebSocketUrl = (): string => { if (typeof window === "undefined") { @@ -85,16 +65,16 @@ export function ScriptTerminalModal({ const wsUrl = getScriptWebSocketUrl() + const handleWebSocketCreated = (ws: WebSocket) => { + wsRef.current = ws + } + const handleWebInteraction = (interaction: WebInteraction) => { - console.log("[v0] handleWebInteraction called with:", interaction) setCurrentInteraction(interaction) - console.log("[v0] currentInteraction set to:", interaction.type, interaction.id) } const handleInteractionResponse = (value: string) => { - console.log("[v0] handleInteractionResponse called with value:", value) - if (!terminalRef.current || !currentInteraction) { - console.log("[v0] Cannot send response - no terminal ref or interaction") + if (!wsRef.current || !currentInteraction) { return } @@ -104,12 +84,10 @@ export function ScriptTerminalModal({ value: value, }) - console.log("[v0] Sending interaction response:", response) + if (wsRef.current.readyState === WebSocket.OPEN) { + wsRef.current.send(response) + } - terminalRef.current.sendMessage(response) - console.log("[v0] Response sent successfully") - - console.log("[v0] Clearing currentInteraction after response") setCurrentInteraction(null) setInteractionInput("") } @@ -144,13 +122,13 @@ export function ScriptTerminalModal({
@@ -163,17 +141,11 @@ export function ScriptTerminalModal({ {currentInteraction && ( - + { - console.log("[v0] onInteractOutside triggered - preventing close") - e.preventDefault() - }} - onEscapeKeyDown={(e) => { - console.log("[v0] onEscapeKeyDown triggered - preventing close") - e.preventDefault() - }} + onInteractOutside={(e) => e.preventDefault()} + onEscapeKeyDown={(e) => e.preventDefault()} > {currentInteraction.title}
@@ -212,25 +184,24 @@ export function ScriptTerminalModal({
)} - {currentInteraction.type === "input" || - (currentInteraction.type === "inputbox" && ( -
- - setInteractionInput(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter") { - handleInteractionResponse(interactionInput) - } - }} - placeholder={currentInteraction.default || ""} - /> - -
- ))} + {(currentInteraction.type === "input" || currentInteraction.type === "inputbox") && ( +
+ + setInteractionInput(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") { + handleInteractionResponse(interactionInput) + } + }} + placeholder={currentInteraction.default || ""} + /> + +
+ )} {currentInteraction.type === "msgbox" && ( - - - )} - - - - - + activeTerminal.ws.send(seq) + } + + const handleClear = () => { + const activeTerminal = terminals.find((t) => t.id === activeTerminalId) + if (activeTerminal?.term) { + activeTerminal.term.clear() + } + } + + const handleClose = () => { + terminals.forEach((terminal) => { + if (terminal.ws) terminal.ws.close() + if (terminal.term) terminal.term.dispose() + }) + onClose?.() + } + + const sendToActiveTerminal = (command: string) => { + const activeTerminal = terminals.find((t) => t.id === activeTerminalId) + + if (activeTerminal?.ws && activeTerminal.ws.readyState === WebSocket.OPEN) { + activeTerminal.ws.send(command) + + setTimeout(() => { + setSearchModalOpen(false) + }, 100) + } + } + + const sendSequence = (seq: string, e?: React.MouseEvent | React.TouchEvent) => { + if (e) { + e.preventDefault() + e.stopPropagation() + } + + const activeTerminal = terminals.find((t) => t.id === activeTerminalId) + if (activeTerminal?.ws && activeTerminal.ws.readyState === WebSocket.OPEN) { + activeTerminal.ws.send(seq) + } + } + + const getLayoutClass = () => { + const count = terminals.length + if (isMobile || count === 1) return "grid grid-cols-1" + + // Vista de cuadrícula 2x2 + if (layout === "grid") { + if (count === 2) return "grid grid-cols-2" + if (count === 3) return "grid grid-cols-2 grid-rows-2" + if (count === 4) return "grid grid-cols-2 grid-rows-2" + } + + if (count === 2) return "grid grid-cols-1 grid-rows-2" + if (count === 3) return "grid grid-cols-1 grid-rows-3" + if (count === 4) return "grid grid-cols-1 grid-rows-4" + + // Vista de filas apiladas (single) - una terminal debajo de otra + return "grid grid-cols-1" + } + + const activeTerminal = terminals.find((t) => t.id === activeTerminalId) + + return ( +
+
+
+ +
+ {terminals.length} / 4 terminals
-
{ - containerRefs.current["main"] = el - }} - className={`overflow-hidden flex flex-col ${isMobile ? "flex-1 h-[60vh]" : "overflow-hidden"} w-full max-w-full`} - style={!isMobile || isTablet ? { height: `${terminalHeight}px`, flexShrink: 0 } : undefined} - > - {isMobile ? ( - - - {terminals.map((terminal) => ( - +
+ {!isMobile && terminals.length > 1 && ( + <> + + + + )} + + + + +
+
+ +
{ + containerRefs.current["main"] = el + }} + className={`overflow-hidden flex flex-col ${isMobile ? "flex-1 h-[60vh]" : "overflow-hidden"} w-full max-w-full`} + style={!isMobile || isTablet ? { height: `${terminalHeight}px`, flexShrink: 0 } : undefined} + > + {isMobile ? ( + + + {terminals.map((terminal) => ( + + {terminal.title} + {terminals.length > 1 && ( + + )} + + ))} + + {terminals.map((terminal) => ( + +
(containerRefs.current[terminal.id] = el)} + className="w-full h-full flex-1 bg-black overflow-hidden" + /> + + ))} + + ) : ( +
+ {terminals.map((terminal) => ( +
1 && activeTerminalId === terminal.id ? "ring-2 ring-blue-500" : "" + }`} + > +
+ + )} +
+
(containerRefs.current[terminal.id] = el)} + onClick={() => setActiveTerminalId(terminal.id)} + className="flex-1 w-full max-w-full bg-black overflow-hidden cursor-pointer" + data-terminal-container + /> +
+ ))} +
+ )} +
+ + {(isTablet || (!isMobile && !isTablet)) && terminals.length > 0 && ( +
+ +
+ )} + + {(isMobile || isTablet) && ( +
+ + + + + + + +
+ )} + + + + + Search Commands +
+
+
+ + + Search for Linux and Proxmox commands + +
+
+ + setSearchQuery(e.target.value)} + className="pl-10 bg-zinc-900 border-zinc-700 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 text-base" + autoCapitalize="none" + autoComplete="off" + autoCorrect="off" + spellCheck={false} + /> +
+ + {isSearching && ( +
+
+

Searching cheat.sh...

+
+ )} + +
+ {searchResults.length > 0 ? ( + <> + {searchResults.map((result, index) => ( +
+ {result.description && ( +

# {result.description}

+ )} +
sendToActiveTerminal(result.command)} + className="flex items-start justify-between gap-2 cursor-pointer group hover:bg-zinc-800/50 rounded p-2 -m-2" + > + {result.command} + +
+
+ ))} + +
+

+ + Powered by cheat.sh +

+
+ + ) : filteredCommands.length > 0 && !useOnline ? ( + filteredCommands.map((item, index) => ( +
sendToActiveTerminal(item.cmd)} + className="p-3 rounded-lg border border-zinc-700 bg-zinc-800/50 hover:bg-zinc-800 hover:border-blue-500 cursor-pointer transition-colors" + > +
+
+ {item.cmd} +

{item.desc}

+
+ - )} - - ))} - - {terminals.map((terminal) => ( - -
(containerRefs.current[terminal.id] = el)} - className="w-full h-full flex-1 bg-black overflow-hidden" - /> - - ))} - - ) : ( -
- {terminals.map((terminal) => ( -
1 && activeTerminalId === terminal.id ? "ring-2 ring-blue-500" : "" - }`} - > -
- - {terminals.length > 1 && ( - - )} + + Send + +
+ )) + ) : !isSearching && !searchQuery && !useOnline ? ( + proxmoxCommands.map((item, index) => (
(containerRefs.current[terminal.id] = el)} - onClick={() => setActiveTerminalId(terminal.id)} - className="flex-1 w-full max-w-full bg-black overflow-hidden cursor-pointer" - data-terminal-container - /> + key={index} + onClick={() => sendToActiveTerminal(item.cmd)} + className="p-3 rounded-lg border border-zinc-700 bg-zinc-800/50 hover:bg-zinc-800 hover:border-blue-500 cursor-pointer transition-colors" + > +
+
+ {item.cmd} +

{item.desc}

+
+ +
+
+ )) + ) : !isSearching ? ( +
+ {searchQuery ? ( + <> + +
+

No results found for "{searchQuery}"

+

Try a different command or check your spelling

+
+ + ) : ( + <> + +
+

Search for any command

+
+

Try searching for:

+
+ {["tar", "grep", "docker", "qm", "systemctl"].map((cmd) => ( + setSearchQuery(cmd)} + className="px-2 py-1 bg-zinc-800 rounded text-blue-400 cursor-pointer hover:bg-zinc-700" + > + {cmd} + + ))} +
+
+
+ {useOnline && ( +
+ + Powered by cheat.sh +
+ )} + + )}
- ))} + ) : null}
- )} -
- {(isTablet || (!isMobile && !isTablet)) && terminals.length > 0 && ( -
- -
- )} - - {(isMobile || isTablet) && ( -
- - - - - - - -
- )} - - - - - Search Commands +
-
-
- - - Search for Linux and Proxmox commands - -
-
- - setSearchQuery(e.target.value)} - className="pl-10 bg-zinc-900 border-zinc-700 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 text-base" - autoCapitalize="none" - autoComplete="off" - autoCorrect="off" - spellCheck={false} - /> -
- - {isSearching && ( -
-
-

Searching cheat.sh...

-
- )} - -
- {searchResults.length > 0 ? ( - <> - {searchResults.map((result, index) => ( -
- {result.description && ( -

# {result.description}

- )} -
sendToActiveTerminal(result.command)} - className="flex items-start justify-between gap-2 cursor-pointer group hover:bg-zinc-800/50 rounded p-2 -m-2" - > - {result.command} - -
-
- ))} - -
-

- - Powered by cheat.sh -

-
- - ) : filteredCommands.length > 0 && !useOnline ? ( - filteredCommands.map((item, index) => ( -
sendToActiveTerminal(item.cmd)} - className="p-3 rounded-lg border border-zinc-700 bg-zinc-800/50 hover:bg-zinc-800 hover:border-blue-500 cursor-pointer transition-colors" - > -
-
- {item.cmd} -

{item.desc}

-
- -
-
- )) - ) : !isSearching && !searchQuery && !useOnline ? ( - proxmoxCommands.map((item, index) => ( -
sendToActiveTerminal(item.cmd)} - className="p-3 rounded-lg border border-zinc-700 bg-zinc-800/50 hover:bg-zinc-800 hover:border-blue-500 cursor-pointer transition-colors" - > -
-
- {item.cmd} -

{item.desc}

-
- -
-
- )) - ) : !isSearching ? ( -
- {searchQuery ? ( - <> - -
-

No results found for "{searchQuery}"

-

Try a different command or check your spelling

-
- - ) : ( - <> - -
-

Search for any command

-
-

Try searching for:

-
- {["tar", "grep", "docker", "qm", "systemctl"].map((cmd) => ( - setSearchQuery(cmd)} - className="px-2 py-1 bg-zinc-800 rounded text-blue-400 cursor-pointer hover:bg-zinc-700" - > - {cmd} - - ))} -
-
-
- {useOnline && ( -
- - Powered by cheat.sh -
- )} - - )} -
- ) : null} -
- -
-
- - Tip: Search for any Linux command or Proxmox commands (qm, pct, zpool) -
- {useOnline && searchResults.length > 0 && Powered by cheat.sh} + + Tip: Search for any Linux command or Proxmox commands (qm, pct, zpool)
+ {useOnline && searchResults.length > 0 && Powered by cheat.sh}
- -
-
- ) - }, -) - -TerminalPanel.displayName = "TerminalPanel" - -export default TerminalPanel +
+ +
+
+ ) +}