mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-04-28 18:36:31 +00:00
Update terminal panel
This commit is contained in:
@@ -31,8 +31,8 @@ import {
|
|||||||
import { DialogHeader, DialogDescription } from "@/components/ui/dialog"
|
import { DialogHeader, DialogDescription } from "@/components/ui/dialog"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Dialog as SearchDialog, DialogContent as SearchDialogContent, DialogTitle as SearchDialogTitle } from "@/components/ui/dialog"
|
import { Dialog as SearchDialog, DialogContent as SearchDialogContent, DialogTitle as SearchDialogTitle } from "@/components/ui/dialog"
|
||||||
import "xterm/css/xterm.css"
|
import "@xterm/xterm/css/xterm.css"
|
||||||
import { API_PORT, fetchApi } from "@/lib/api-config"
|
import { fetchApi, getWebSocketUrl } from "@/lib/api-config"
|
||||||
|
|
||||||
interface LxcTerminalModalProps {
|
interface LxcTerminalModalProps {
|
||||||
open: boolean
|
open: boolean
|
||||||
@@ -75,21 +75,7 @@ const proxmoxCommands = [
|
|||||||
{ cmd: "clear", desc: "Clear terminal screen" },
|
{ cmd: "clear", desc: "Clear terminal screen" },
|
||||||
]
|
]
|
||||||
|
|
||||||
function getWebSocketUrl(): string {
|
// Use centralized getWebSocketUrl from api-config
|
||||||
if (typeof window === "undefined") {
|
|
||||||
return "ws://localhost:8008/ws/terminal"
|
|
||||||
}
|
|
||||||
|
|
||||||
const { protocol, hostname, port } = window.location
|
|
||||||
const isStandardPort = port === "" || port === "80" || port === "443"
|
|
||||||
const wsProtocol = protocol === "https:" ? "wss:" : "ws:"
|
|
||||||
|
|
||||||
if (isStandardPort) {
|
|
||||||
return `${wsProtocol}//${hostname}/ws/terminal`
|
|
||||||
} else {
|
|
||||||
return `${wsProtocol}//${hostname}:${API_PORT}/ws/terminal`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LxcTerminalModal({
|
export function LxcTerminalModal({
|
||||||
open: isOpen,
|
open: isOpen,
|
||||||
@@ -169,8 +155,8 @@ export function LxcTerminalModal({
|
|||||||
|
|
||||||
const initTerminal = async () => {
|
const initTerminal = async () => {
|
||||||
const [TerminalClass, FitAddonClass] = await Promise.all([
|
const [TerminalClass, FitAddonClass] = await Promise.all([
|
||||||
import("xterm").then((mod) => mod.Terminal),
|
import("@xterm/xterm").then((mod) => mod.Terminal),
|
||||||
import("xterm-addon-fit").then((mod) => mod.FitAddon),
|
import("@xterm/addon-fit").then((mod) => mod.FitAddon),
|
||||||
])
|
])
|
||||||
|
|
||||||
const fontSize = window.innerWidth < 768 ? 12 : 16
|
const fontSize = window.innerWidth < 768 ? 12 : 16
|
||||||
@@ -222,7 +208,7 @@ export function LxcTerminalModal({
|
|||||||
fitAddonRef.current = fitAddon
|
fitAddonRef.current = fitAddon
|
||||||
|
|
||||||
// Connect WebSocket to host terminal
|
// Connect WebSocket to host terminal
|
||||||
const wsUrl = getWebSocketUrl()
|
const wsUrl = getWebSocketUrl("/ws/terminal")
|
||||||
const ws = new WebSocket(wsUrl)
|
const ws = new WebSocket(wsUrl)
|
||||||
wsRef.current = ws
|
wsRef.current = ws
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuLabel,
|
DropdownMenuLabel,
|
||||||
} from "@/components/ui/dropdown-menu"
|
} from "@/components/ui/dropdown-menu"
|
||||||
import "xterm/css/xterm.css"
|
import "@xterm/xterm/css/xterm.css"
|
||||||
import { API_PORT } from "@/lib/api-config"
|
import { getWebSocketUrl } from "@/lib/api-config"
|
||||||
|
|
||||||
interface WebInteraction {
|
interface WebInteraction {
|
||||||
type: "yesno" | "menu" | "msgbox" | "input" | "inputbox"
|
type: "yesno" | "menu" | "msgbox" | "input" | "inputbox"
|
||||||
@@ -96,7 +96,7 @@ export function ScriptTerminalModal({
|
|||||||
wsRef.current.close()
|
wsRef.current.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
const wsUrl = getScriptWebSocketUrl(sessionIdRef.current)
|
const wsUrl = getScriptWebSocketUrlLocal(sessionIdRef.current)
|
||||||
const ws = new WebSocket(wsUrl)
|
const ws = new WebSocket(wsUrl)
|
||||||
wsRef.current = ws
|
wsRef.current = ws
|
||||||
|
|
||||||
@@ -202,9 +202,9 @@ export function ScriptTerminalModal({
|
|||||||
|
|
||||||
const initializeTerminal = async () => {
|
const initializeTerminal = async () => {
|
||||||
const [TerminalClass, FitAddonClass] = await Promise.all([
|
const [TerminalClass, FitAddonClass] = await Promise.all([
|
||||||
import("xterm").then((mod) => mod.Terminal),
|
import("@xterm/xterm").then((mod) => mod.Terminal),
|
||||||
import("xterm-addon-fit").then((mod) => mod.FitAddon),
|
import("@xterm/addon-fit").then((mod) => mod.FitAddon),
|
||||||
import("xterm/css/xterm.css"),
|
import("@xterm/xterm/css/xterm.css"),
|
||||||
])
|
])
|
||||||
|
|
||||||
const fontSize = window.innerWidth < 768 ? 12 : 16
|
const fontSize = window.innerWidth < 768 ? 12 : 16
|
||||||
@@ -259,7 +259,7 @@ export function ScriptTerminalModal({
|
|||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
const wsUrl = getScriptWebSocketUrl(sessionIdRef.current)
|
const wsUrl = getScriptWebSocketUrlLocal(sessionIdRef.current)
|
||||||
const ws = new WebSocket(wsUrl)
|
const ws = new WebSocket(wsUrl)
|
||||||
wsRef.current = ws
|
wsRef.current = ws
|
||||||
|
|
||||||
@@ -493,20 +493,9 @@ export function ScriptTerminalModal({
|
|||||||
}
|
}
|
||||||
}, [isOpen, isComplete, attemptReconnect])
|
}, [isOpen, isComplete, attemptReconnect])
|
||||||
|
|
||||||
const getScriptWebSocketUrl = (sid: string): string => {
|
// Use centralized getWebSocketUrl from api-config
|
||||||
if (typeof window === "undefined") {
|
const getScriptWebSocketUrlLocal = (sid: string): string => {
|
||||||
return `ws://localhost:${API_PORT}/ws/script/${sid}`
|
return getWebSocketUrl(`/ws/script/${sid}`)
|
||||||
}
|
|
||||||
|
|
||||||
const { protocol, hostname, port } = window.location
|
|
||||||
const isStandardPort = port === "" || port === "80" || port === "443"
|
|
||||||
const wsProtocol = protocol === "https:" ? "wss:" : "ws:"
|
|
||||||
|
|
||||||
if (isStandardPort) {
|
|
||||||
return `${wsProtocol}//${hostname}/ws/script/${sid}`
|
|
||||||
} else {
|
|
||||||
return `${wsProtocol}//${hostname}:${API_PORT}/ws/script/${sid}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleInteractionResponse = (value: string) => {
|
const handleInteractionResponse = (value: string) => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import type React from "react"
|
import type React from "react"
|
||||||
import { useEffect, useRef, useState } from "react"
|
import { useEffect, useRef, useState } from "react"
|
||||||
import { API_PORT, fetchApi } from "@/lib/api-config" // Unificando importaciones de api-config en una sola línea con alias @/
|
import { API_PORT, fetchApi, getWebSocketUrl as getWebSocketUrlFromConfig, getApiUrl as getApiUrlFromConfig } from "@/lib/api-config"
|
||||||
import {
|
import {
|
||||||
Activity,
|
Activity,
|
||||||
Trash2,
|
Trash2,
|
||||||
@@ -46,31 +46,13 @@ interface TerminalInstance {
|
|||||||
pingInterval?: ReturnType<typeof setInterval> | null // Heartbeat interval to keep connection alive
|
pingInterval?: ReturnType<typeof setInterval> | null // Heartbeat interval to keep connection alive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use centralized functions from api-config.ts for SSL/proxy support
|
||||||
function getWebSocketUrl(): string {
|
function getWebSocketUrl(): string {
|
||||||
if (typeof window === "undefined") {
|
return getWebSocketUrlFromConfig("/ws/terminal")
|
||||||
return "ws://localhost:8008/ws/terminal"
|
|
||||||
}
|
|
||||||
|
|
||||||
const { protocol, hostname, port } = window.location
|
|
||||||
const isStandardPort = port === "" || port === "80" || port === "443"
|
|
||||||
|
|
||||||
const wsProtocol = protocol === "https:" ? "wss:" : "ws:"
|
|
||||||
|
|
||||||
if (isStandardPort) {
|
|
||||||
return `${wsProtocol}//${hostname}/ws/terminal`
|
|
||||||
} else {
|
|
||||||
return `${wsProtocol}//${hostname}:${API_PORT}/ws/terminal`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getApiUrl(endpoint?: string): string {
|
function getApiUrl(endpoint?: string): string {
|
||||||
if (typeof window === "undefined") {
|
return getApiUrlFromConfig(endpoint || "")
|
||||||
return "http://localhost:8008"
|
|
||||||
}
|
|
||||||
|
|
||||||
const { protocol, hostname } = window.location
|
|
||||||
const apiProtocol = protocol === "https:" ? "https:" : "http:"
|
|
||||||
return `${apiProtocol}//${hostname}:${API_PORT}${endpoint || ""}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const proxmoxCommands = [
|
const proxmoxCommands = [
|
||||||
@@ -472,9 +454,9 @@ export const TerminalPanel: React.FC<TerminalPanelProps> = ({ websocketUrl, onCl
|
|||||||
|
|
||||||
const initializeTerminal = async (terminal: TerminalInstance, container: HTMLDivElement) => {
|
const initializeTerminal = async (terminal: TerminalInstance, container: HTMLDivElement) => {
|
||||||
const [TerminalClass, FitAddonClass] = await Promise.all([
|
const [TerminalClass, FitAddonClass] = await Promise.all([
|
||||||
import("xterm").then((mod) => mod.Terminal),
|
import("@xterm/xterm").then((mod) => mod.Terminal),
|
||||||
import("xterm-addon-fit").then((mod) => mod.FitAddon),
|
import("@xterm/addon-fit").then((mod) => mod.FitAddon),
|
||||||
import("xterm/css/xterm.css"),
|
import("@xterm/xterm/css/xterm.css"),
|
||||||
]).then(([Terminal, FitAddon]) => [Terminal, FitAddon])
|
]).then(([Terminal, FitAddon]) => [Terminal, FitAddon])
|
||||||
|
|
||||||
const fontSize = window.innerWidth < 768 ? 12 : 16
|
const fontSize = window.innerWidth < 768 ? 12 : 16
|
||||||
|
|||||||
@@ -50,6 +50,41 @@ export function getApiUrl(endpoint: string): string {
|
|||||||
return `${baseUrl}${normalizedEndpoint}`
|
return `${baseUrl}${normalizedEndpoint}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the base URL for WebSocket connections
|
||||||
|
* Automatically handles ws:// vs wss:// based on page protocol (SSL support)
|
||||||
|
*
|
||||||
|
* @param path - WebSocket endpoint path (e.g., '/ws/terminal')
|
||||||
|
* @returns Full WebSocket URL
|
||||||
|
*/
|
||||||
|
export function getWebSocketUrl(path: string): string {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return `ws://localhost:${API_PORT}${path}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { protocol, hostname, port } = window.location
|
||||||
|
const isStandardPort = port === "" || port === "80" || port === "443"
|
||||||
|
|
||||||
|
// Use wss:// when page is served over https://
|
||||||
|
const wsProtocol = protocol === "https:" ? "wss:" : "ws:"
|
||||||
|
|
||||||
|
// Ensure path starts with /
|
||||||
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`
|
||||||
|
|
||||||
|
let wsUrl: string
|
||||||
|
if (isStandardPort) {
|
||||||
|
// Behind a proxy - WebSocket goes through same host
|
||||||
|
wsUrl = `${wsProtocol}//${hostname}${normalizedPath}`
|
||||||
|
} else {
|
||||||
|
// Direct access - use API port
|
||||||
|
wsUrl = `${wsProtocol}//${hostname}:${API_PORT}${normalizedPath}`
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[v0] getWebSocketUrl: protocol=${protocol}, hostname=${hostname}, port=${port}, isStandardPort=${isStandardPort}, wsUrl=${wsUrl}`)
|
||||||
|
|
||||||
|
return wsUrl
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the JWT token from localStorage
|
* Gets the JWT token from localStorage
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
"geist": "^1.3.1",
|
"geist": "^1.3.1",
|
||||||
"input-otp": "1.4.1",
|
"input-otp": "1.4.1",
|
||||||
"lucide-react": "^0.454.0",
|
"lucide-react": "^0.454.0",
|
||||||
"next": "15.1.6",
|
"next": "15.2.4",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19",
|
"react": "^19",
|
||||||
"react-day-picker": "9.8.0",
|
"react-day-picker": "9.8.0",
|
||||||
@@ -61,8 +61,8 @@
|
|||||||
"tailwind-merge": "^3.3.1",
|
"tailwind-merge": "^3.3.1",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vaul": "^0.9.9",
|
"vaul": "^0.9.9",
|
||||||
"xterm": "^5.3.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"xterm-addon-fit": "^0.8.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"zod": "3.25.67"
|
"zod": "3.25.67"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
Reference in New Issue
Block a user