diff --git a/scripts/ct/debian.sh b/scripts/ct/debian.sh new file mode 100644 index 0000000..54b1748 --- /dev/null +++ b/scripts/ct/debian.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +SCRIPT_DIR="$(dirname "$0")" +source "$SCRIPT_DIR/../core/build.func" +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://www.debian.org/ + +APP="Debian" +var_tags="${var_tags:-os}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-2}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /var ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + msg_info "Updating $APP LXC" + $STD apt update + $STD apt -y upgrade + msg_ok "Updated $APP LXC" + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" diff --git a/scripts/install/debian-install.sh b/scripts/install/debian-install.sh new file mode 100644 index 0000000..7b00eca --- /dev/null +++ b/scripts/install/debian-install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://www.debian.org/ + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +motd_ssh +customize + +msg_info "Cleaning up" +$STD apt -y autoremove +$STD apt -y autoclean +$STD apt -y clean +msg_ok "Cleaned" + diff --git a/src/app/_components/DownloadedScriptsTab.tsx b/src/app/_components/DownloadedScriptsTab.tsx index dfb5af4..7e18354 100644 --- a/src/app/_components/DownloadedScriptsTab.tsx +++ b/src/app/_components/DownloadedScriptsTab.tsx @@ -9,7 +9,16 @@ import { FilterBar, type FilterState } from './FilterBar'; import { Button } from './ui/button'; import type { ScriptCard as ScriptCardType } from '~/types/script'; -export function DownloadedScriptsTab() { +interface DownloadedScriptsTabProps { + onInstallScript?: ( + scriptPath: string, + scriptName: string, + mode?: "local" | "ssh", + server?: any, + ) => void; +} + +export function DownloadedScriptsTab({ onInstallScript }: DownloadedScriptsTabProps) { const [selectedSlug, setSelectedSlug] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [selectedCategory, setSelectedCategory] = useState(null); @@ -462,9 +471,7 @@ export function DownloadedScriptsTab() { script={scriptData?.success ? scriptData.script : null} isOpen={isModalOpen} onClose={handleCloseModal} - onInstallScript={() => { - // Downloaded scripts don't need installation - }} + onInstallScript={onInstallScript} /> diff --git a/src/app/_components/ScriptDetailModal.tsx b/src/app/_components/ScriptDetailModal.tsx index 7b85b87..8e45941 100644 --- a/src/app/_components/ScriptDetailModal.tsx +++ b/src/app/_components/ScriptDetailModal.tsx @@ -120,9 +120,6 @@ export function ScriptDetailModal({ // Pass execution mode and server info to the parent onInstallScript(scriptPath, scriptName, mode, server); - // Scroll to top of the page to see the terminal - window.scrollTo({ top: 0, behavior: "smooth" }); - onClose(); // Close the modal when starting installation } }; diff --git a/src/app/_components/Terminal.tsx b/src/app/_components/Terminal.tsx index c59e23d..ee1f93f 100644 --- a/src/app/_components/Terminal.tsx +++ b/src/app/_components/Terminal.tsx @@ -29,6 +29,7 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate const [lastInputSent, setLastInputSent] = useState(null); const [inWhiptailSession, setInWhiptailSession] = useState(false); const [isMobile, setIsMobile] = useState(false); + const [isStopped, setIsStopped] = useState(false); const terminalRef = useRef(null); const xtermRef = useRef(null); const fitAddonRef = useRef(null); @@ -64,23 +65,8 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate if (message.data.includes('\x1b[2J') || message.data.includes('\x1b[H\x1b[2J')) { // This is a clear screen sequence, ensure it's processed correctly xtermRef.current.write(message.data); - } else if (message.data.includes('\x1b[') && message.data.includes('H')) { - // This is a cursor positioning sequence, often implies a redraw of the entire screen - if (inWhiptailSession) { - // In whiptail session, completely reset the terminal - // Completely clear everything - xtermRef.current.clear(); - xtermRef.current.write('\x1b[2J\x1b[H\x1b[3J\x1b[2J'); - // Reset the terminal state - xtermRef.current.reset(); - // Write the new content after reset - setTimeout(() => { - xtermRef.current.write(message.data); - }, 100); - } else { - xtermRef.current.write(message.data); - } } else { + // Let xterm handle all ANSI sequences naturally xtermRef.current.write(message.data); } break; @@ -153,9 +139,27 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate const terminal = new XTerm({ theme: { - background: '#000000', - foreground: '#00ff00', - cursor: '#00ff00', + background: '#0d1117', + foreground: '#e6edf3', + cursor: '#58a6ff', + cursorAccent: '#0d1117', + // Let ANSI colors work naturally - only define basic colors + 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', }, fontSize: isMobile ? 7 : 14, fontFamily: 'JetBrains Mono, Fira Code, Cascadia Code, Monaco, Menlo, Ubuntu Mono, monospace', @@ -189,6 +193,13 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate // Open terminal terminal.open(terminalElement); + // Ensure proper terminal rendering + setTimeout(() => { + terminal.refresh(0, terminal.rows - 1); + // Ensure cursor is properly positioned + terminal.focus(); + }, 100); + // Fit after a small delay to ensure proper sizing setTimeout(() => { fitAddon.fit(); @@ -269,6 +280,7 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate } isConnectingRef.current = true; + const isInitialConnection = !hasConnectedRef.current; hasConnectedRef.current = true; // Small delay to prevent rapid reconnection @@ -284,17 +296,19 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate setIsConnected(true); isConnectingRef.current = false; - // Send start message immediately after connection - const message = { - action: 'start', - scriptPath, - executionId, - mode, - server, - isUpdate, - containerId - }; - ws.send(JSON.stringify(message)); + // Only auto-start on initial connection, not on reconnections + if (isInitialConnection && !isRunning) { + const message = { + action: 'start', + scriptPath, + executionId, + mode, + server, + isUpdate, + containerId + }; + ws.send(JSON.stringify(message)); + } }; ws.onmessage = (event) => { @@ -335,7 +349,8 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate }, [scriptPath, executionId, mode, server, isUpdate, containerId, handleMessage, isMobile]); const startScript = () => { - if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) { + if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN && !isRunning) { + setIsStopped(false); wsRef.current.send(JSON.stringify({ action: 'start', scriptPath, @@ -350,6 +365,8 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate const stopScript = () => { if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) { + setIsStopped(true); + setIsRunning(false); wsRef.current.send(JSON.stringify({ action: 'stop', executionId @@ -586,10 +603,10 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate