From ae58c265a085a7f215be04bad5cbc0a90d42a2df Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sat, 22 Nov 2025 11:04:21 +0100 Subject: [PATCH] Update AppImage --- AppImage/components/proxmox-dashboard.tsx | 4 +- AppImage/components/terminal-panel.tsx | 249 ++++++++++++++-------- 2 files changed, 166 insertions(+), 87 deletions(-) diff --git a/AppImage/components/proxmox-dashboard.tsx b/AppImage/components/proxmox-dashboard.tsx index 406f67a..214c81f 100644 --- a/AppImage/components/proxmox-dashboard.tsx +++ b/AppImage/components/proxmox-dashboard.tsx @@ -633,9 +633,7 @@ export function ProxmoxDashboard() { -
- -
+
diff --git a/AppImage/components/terminal-panel.tsx b/AppImage/components/terminal-panel.tsx index 9bbe476..3426e1b 100644 --- a/AppImage/components/terminal-panel.tsx +++ b/AppImage/components/terminal-panel.tsx @@ -3,9 +3,11 @@ import type React from "react" import { useEffect, useRef, useState } from "react" import { API_PORT } from "@/lib/api-config" -import { Trash2, X, Send, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Activity } from "lucide-react" +import { Trash2, X, Send, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Search } from "lucide-react" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" type TerminalPanelProps = { websocketUrl?: string @@ -29,6 +31,47 @@ function getWebSocketUrl(): string { } } +const commonCommands = [ + { cmd: "ls -la", desc: "List all files with details" }, + { cmd: "cd /path/to/dir", desc: "Change directory" }, + { cmd: "mkdir dirname", desc: "Create new directory" }, + { cmd: "rm -rf dirname", desc: "Remove directory recursively" }, + { cmd: "cp source dest", desc: "Copy files or directories" }, + { cmd: "mv source dest", desc: "Move or rename files" }, + { cmd: "cat filename", desc: "Display file contents" }, + { cmd: "grep 'pattern' file", desc: "Search for pattern in file" }, + { cmd: "find . -name 'file'", desc: "Find files by name" }, + { cmd: "chmod 755 file", desc: "Change file permissions" }, + { cmd: "chown user:group file", desc: "Change file owner" }, + { cmd: "tar -xzf file.tar.gz", desc: "Extract tar.gz archive" }, + { cmd: "tar -czf archive.tar.gz dir/", desc: "Create tar.gz archive" }, + { cmd: "df -h", desc: "Show disk usage" }, + { cmd: "du -sh *", desc: "Show directory sizes" }, + { cmd: "free -h", desc: "Show memory usage" }, + { cmd: "top", desc: "Show running processes" }, + { cmd: "ps aux | grep process", desc: "Find running process" }, + { cmd: "kill -9 PID", desc: "Force kill process" }, + { cmd: "systemctl status service", desc: "Check service status" }, + { cmd: "systemctl start service", desc: "Start a service" }, + { cmd: "systemctl stop service", desc: "Stop a service" }, + { cmd: "systemctl restart service", desc: "Restart a service" }, + { cmd: "apt update && apt upgrade", desc: "Update Debian/Ubuntu packages" }, + { cmd: "apt install package", desc: "Install package on Debian/Ubuntu" }, + { cmd: "apt remove package", desc: "Remove package" }, + { cmd: "docker ps", desc: "List running containers" }, + { cmd: "docker images", desc: "List Docker images" }, + { cmd: "docker exec -it container bash", desc: "Enter container shell" }, + { cmd: "ip addr show", desc: "Show IP addresses" }, + { cmd: "ping host", desc: "Test network connectivity" }, + { cmd: "curl -I url", desc: "Get HTTP headers" }, + { cmd: "wget url", desc: "Download file from URL" }, + { cmd: "ssh user@host", desc: "Connect via SSH" }, + { cmd: "scp file user@host:/path", desc: "Copy file via SSH" }, + { cmd: "tail -f /var/log/syslog", desc: "Follow log file in real-time" }, + { cmd: "history", desc: "Show command history" }, + { cmd: "clear", desc: "Clear terminal screen" }, +] + export const TerminalPanel: React.FC = ({ websocketUrl, onClose }) => { const containerRef = useRef(null) const termRef = useRef(null) @@ -38,7 +81,9 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl const [xtermLoaded, setXtermLoaded] = useState(false) const [isConnected, setIsConnected] = useState(false) - const [mobileInput, setMobileInput] = useState("") + const [searchModalOpen, setSearchModalOpen] = useState(false) + const [searchQuery, setSearchQuery] = useState("") + const [filteredCommands, setFilteredCommands] = useState(commonCommands) const [lastKeyPressed, setLastKeyPressed] = useState(null) const [isMobile, setIsMobile] = useState(false) @@ -49,6 +94,18 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl return () => window.removeEventListener("resize", handleResize) }, []) + useEffect(() => { + if (!searchQuery.trim()) { + setFilteredCommands(commonCommands) + return + } + const query = searchQuery.toLowerCase() + const filtered = commonCommands.filter( + (item) => item.cmd.toLowerCase().includes(query) || item.desc.toLowerCase().includes(query), + ) + setFilteredCommands(filtered) + }, [searchQuery]) + useEffect(() => { if (typeof window === "undefined") return @@ -60,8 +117,6 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl .then(([Terminal, FitAddon]) => { if (!containerRef.current) return - console.log("[v0] TerminalPanel: Initializing terminal") - const term = new Terminal({ fontFamily: "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace", fontSize: isMobile ? 11 : 13, @@ -71,26 +126,26 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl cols: 150, rows: 30, theme: { - background: "#0d1117", - foreground: "#e6edf3", - cursor: "#58a6ff", - cursorAccent: "#0d1117", - black: "#484f58", - red: "#f85149", - green: "#3fb950", - yellow: "#d29922", - blue: "#58a6ff", - magenta: "#bc8cff", - cyan: "#39d353", - white: "#b1bac4", - brightBlack: "#6e7681", - brightRed: "#ff7b72", - brightGreen: "#56d364", - brightYellow: "#e3b341", - brightBlue: "#79c0ff", - brightMagenta: "#d2a8ff", - brightCyan: "#56d364", - brightWhite: "#f0f6fc", + background: "#000000", + foreground: "#ffffff", + cursor: "#ffffff", + cursorAccent: "#000000", + black: "#2e3436", + red: "#cc0000", + green: "#4e9a06", + yellow: "#c4a000", + blue: "#3465a4", + magenta: "#75507b", + cyan: "#06989a", + white: "#d3d7cf", + brightBlack: "#555753", + brightRed: "#ef2929", + brightGreen: "#8ae234", + brightYellow: "#fce94f", + brightBlue: "#729fcf", + brightMagenta: "#ad7fa8", + brightCyan: "#34e2e2", + brightWhite: "#eeeeec", }, }) @@ -105,13 +160,11 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl setXtermLoaded(true) const wsUrl = websocketUrl || getWebSocketUrl() - console.log("[v0] TerminalPanel: Connecting to WebSocket:", wsUrl) const ws = new WebSocket(wsUrl) wsRef.current = ws ws.onopen = () => { - console.log("[v0] TerminalPanel: WebSocket connected") setIsConnected(true) term.writeln("\x1b[32mConnected to ProxMenux terminal.\x1b[0m") } @@ -127,7 +180,6 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl } ws.onclose = () => { - console.log("[v0] TerminalPanel: WebSocket closed") setIsConnected(false) term.writeln("\r\n\x1b[33m[INFO] Connection closed\x1b[0m") } @@ -148,7 +200,6 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl window.addEventListener("resize", handleResize) return () => { - console.log("[v0] TerminalPanel: Cleaning up") window.removeEventListener("resize", handleResize) ws.close() term.dispose() @@ -258,43 +309,49 @@ export const TerminalPanel: React.FC = ({ websocketUrl, onCl } } - const handleMobileInputSend = () => { - if (!mobileInput.trim()) return + const handleSendCommand = (command: string) => { const ws = wsRef.current if (ws && ws.readyState === WebSocket.OPEN) { - ws.send(mobileInput) - setLastKeyPressed(mobileInput) - setTimeout(() => setLastKeyPressed(null), 2000) + ws.send(command + "\r") + setLastKeyPressed(command) + setTimeout(() => setLastKeyPressed(null), 3000) } - setMobileInput("") + setSearchModalOpen(false) + setSearchQuery("") } return ( -
+
-
- - ProxMenux Terminal - -
- {isConnected ? "Connected" : "Disconnected"} -
-
+ +
+ {isConnected ? "Connected" : "Disconnected"} +
+ -
-
- )} -
+ {lastKeyPressed && ( + + Sent: {lastKeyPressed} + + )}
+ + + + + Search Commands + +
+ setSearchQuery(e.target.value)} + className="w-full" + autoFocus + /> +
+ {filteredCommands.length > 0 ? ( + filteredCommands.map((item, index) => ( +
handleSendCommand(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}

+
+ +
+
+ )) + ) : ( +
No commands found matching "{searchQuery}"
+ )} +
+
+
+
) }