From 2f53786ca9fcbcb8fdcfe128290922dd14f194ec Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sat, 6 Dec 2025 20:56:36 +0100 Subject: [PATCH] Update terminal-panel.tsx --- AppImage/components/terminal-panel.tsx | 213 ++++++++++++------------- 1 file changed, 98 insertions(+), 115 deletions(-) diff --git a/AppImage/components/terminal-panel.tsx b/AppImage/components/terminal-panel.tsx index fd62d68..8cbf975 100644 --- a/AppImage/components/terminal-panel.tsx +++ b/AppImage/components/terminal-panel.tsx @@ -4,7 +4,19 @@ import type React from "react" import { useEffect, useRef, useState } from "react" import { API_PORT } from "../lib/api-config" import { fetchApi } from "@/lib/api-config" // Cambiando import para usar fetchApi directamente -import { X, Search, Send, Lightbulb, Terminal, Plus, GripHorizontal } from "lucide-react" +import { + Activity, + Trash2, + X, + Search, + Send, + Lightbulb, + Terminal, + Plus, + AlignJustify, + Grid2X2, + GripHorizontal, +} from "lucide-react" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog" import { Input } from "@/components/ui/input" @@ -17,7 +29,6 @@ type TerminalPanelProps = { initMessage?: Record onWebInteraction?: (interaction: any) => void onWebSocketCreated?: (ws: WebSocket) => void - onTerminalOutput?: () => void isScriptModal?: boolean } @@ -125,15 +136,14 @@ const proxmoxCommands = [ { cmd: "clear", desc: "Clear terminal screen" }, ] -export function TerminalPanel({ +export const TerminalPanel: React.FC = ({ websocketUrl, onClose, initMessage, onWebInteraction, onWebSocketCreated, - onTerminalOutput, isScriptModal = false, -}: TerminalPanelProps) { +}) => { const [terminals, setTerminals] = useState([]) const [activeTerminalId, setActiveTerminalId] = useState("") const [layout, setLayout] = useState<"single" | "grid">("grid") @@ -148,7 +158,6 @@ export function TerminalPanel({ const [useOnline, setUseOnline] = useState(true) const containerRefs = useRef<{ [key: string]: HTMLDivElement | null }>({}) - const panelRef = useRef(null) useEffect(() => { const updateDeviceType = () => { @@ -313,11 +322,6 @@ export function TerminalPanel({ delete containerRefs.current[id] } - const handleCloseTab = (e: React.MouseEvent, id: string) => { - e.stopPropagation() - closeTerminal(id) - } - useEffect(() => { terminals.forEach((terminal) => { const container = containerRefs.current[terminal.id] @@ -354,44 +358,6 @@ export function TerminalPanel({ }) }, [terminalHeight, layout, terminals, isMobile]) - useEffect(() => { - if (!isScriptModal) return - - const mainContainer = containerRefs.current["main"] - if (!mainContainer) return - - const resizeObserver = new ResizeObserver(() => { - terminals.forEach((terminal) => { - if (terminal.term && terminal.fitAddon && terminal.isConnected) { - try { - setTimeout(() => { - terminal.fitAddon?.fit() - if (terminal.ws?.readyState === WebSocket.OPEN) { - const cols = terminal.term?.cols || 80 - const rows = terminal.term?.rows || 24 - terminal.ws.send( - JSON.stringify({ - type: "resize", - cols, - rows, - }), - ) - } - }, 50) - } catch (err) { - // Silently handle resize errors - } - } - }) - }) - - resizeObserver.observe(mainContainer) - - return () => { - resizeObserver.disconnect() - } - }, [terminals, isScriptModal]) - const initializeTerminal = async (terminal: TerminalInstance, container: HTMLDivElement) => { const [TerminalClass, FitAddonClass] = await Promise.all([ import("xterm").then((mod) => mod.Terminal), @@ -494,10 +460,6 @@ export function TerminalPanel({ // Not JSON, it's regular terminal output } - if (onTerminalOutput) { - onTerminalOutput() - } - term.write(event.data) } @@ -636,61 +598,81 @@ export function TerminalPanel({ const activeTerminal = terminals.find((t) => t.id === activeTerminalId) return ( -
- {!isScriptModal && ( -
-
-
- {terminals.map((terminal) => ( - - ))} -
- -
+
+
+
+ +
+ {terminals.length} / 4 terminals
- )} - {/* Terminal Tabs */} - {!isScriptModal && ( -
- {terminals.map((terminal) => ( - - ))} +
+ {!isMobile && terminals.length > 1 && ( + <> + + + + )} + + + +
- )} +
{isScriptModal && (
@@ -704,15 +686,16 @@ export function TerminalPanel({ containerRefs.current["main"] = el }} className={`overflow-hidden flex flex-col ${isMobile ? "flex-1 h-[60vh]" : "overflow-hidden"} w-full max-w-full`} - style={ - isScriptModal - ? { height: "100%", flexShrink: 0 } - : !isMobile || isTablet - ? { height: `${terminalHeight}px`, flexShrink: 0 } - : undefined - } + style={!isMobile || isTablet ? { height: `${terminalHeight}px`, flexShrink: 0 } : undefined} > - {isMobile ? ( + {isScriptModal ? ( + // In script modal: render terminal container directly without tabs +
(containerRefs.current[activeTerminalId] = el)} + className="w-full h-full flex-1 bg-black overflow-hidden" + /> + ) : // Normal terminal page: show tabs/grid as usual + isMobile ? ( {terminals.map((terminal) => ( @@ -760,7 +743,7 @@ export function TerminalPanel({ onClick={() => setActiveTerminalId(terminal.id)} className={`text-xs font-medium ${ activeTerminalId === terminal.id ? "text-blue-400" : "text-zinc-500" - } ${isScriptModal ? "hidden" : ""}`} + }`} > {terminal.title} @@ -782,7 +765,7 @@ export function TerminalPanel({ )}
- {!isScriptModal && (isTablet || (!isMobile && !isTablet)) && terminals.length > 0 && ( + {(isTablet || (!isMobile && !isTablet)) && terminals.length > 0 && (