Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions scripts/ct/debian.sh
Original file line number Diff line number Diff line change
@@ -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}"
24 changes: 24 additions & 0 deletions scripts/install/debian-install.sh
Original file line number Diff line number Diff line change
@@ -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"

15 changes: 11 additions & 4 deletions src/app/_components/DownloadedScriptsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
Expand Down Expand Up @@ -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}
/>
</div>
</div>
Expand Down
3 changes: 0 additions & 3 deletions src/app/_components/ScriptDetailModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
};
Expand Down
83 changes: 50 additions & 33 deletions src/app/_components/Terminal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate
const [lastInputSent, setLastInputSent] = useState<string | null>(null);
const [inWhiptailSession, setInWhiptailSession] = useState(false);
const [isMobile, setIsMobile] = useState(false);
const [isStopped, setIsStopped] = useState(false);
const terminalRef = useRef<HTMLDivElement>(null);
const xtermRef = useRef<any>(null);
const fitAddonRef = useRef<any>(null);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand All @@ -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) => {
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -586,10 +603,10 @@ export function Terminal({ scriptPath, onClose, mode = 'local', server, isUpdate
<div className="flex flex-wrap gap-1 sm:gap-2">
<Button
onClick={startScript}
disabled={!isConnected || isRunning}
disabled={!isConnected || (isRunning && !isStopped)}
variant="default"
size="sm"
className={`text-xs sm:text-sm ${isConnected && !isRunning ? 'bg-green-600 hover:bg-green-700' : 'bg-muted text-muted-foreground cursor-not-allowed'}`}
className={`text-xs sm:text-sm ${isConnected && (!isRunning || isStopped) ? 'bg-green-600 hover:bg-green-700' : 'bg-muted text-muted-foreground cursor-not-allowed'}`}
>
<Play className="h-3 w-3 sm:h-4 sm:w-4 mr-1" />
<span className="hidden sm:inline">Start</span>
Expand Down
22 changes: 19 additions & 3 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

'use client';

import { useState } from 'react';
import { useState, useRef } from 'react';
import { ScriptsGrid } from './_components/ScriptsGrid';
import { DownloadedScriptsTab } from './_components/DownloadedScriptsTab';
import { InstalledScriptsTab } from './_components/InstalledScriptsTab';
Expand All @@ -16,9 +16,25 @@ import { Rocket, Package, HardDrive, FolderOpen } from 'lucide-react';
export default function Home() {
const [runningScript, setRunningScript] = useState<{ path: string; name: string; mode?: 'local' | 'ssh'; server?: any } | null>(null);
const [activeTab, setActiveTab] = useState<'scripts' | 'downloaded' | 'installed'>('scripts');
const terminalRef = useRef<HTMLDivElement>(null);

const scrollToTerminal = () => {
if (terminalRef.current) {
// Get the element's position and scroll with a small offset for better mobile experience
const elementTop = terminalRef.current.offsetTop;
const offset = window.innerWidth < 768 ? 20 : 0; // Small offset on mobile

window.scrollTo({
top: elementTop - offset,
behavior: 'smooth'
});
}
};

const handleRunScript = (scriptPath: string, scriptName: string, mode?: 'local' | 'ssh', server?: any) => {
setRunningScript({ path: scriptPath, name: scriptName, mode, server });
// Scroll to terminal after a short delay to ensure it's rendered
setTimeout(scrollToTerminal, 100);
};

const handleCloseTerminal = () => {
Expand Down Expand Up @@ -102,7 +118,7 @@ export default function Home() {

{/* Running Script Terminal */}
{runningScript && (
<div className="mb-8">
<div ref={terminalRef} className="mb-8">
<Terminal
scriptPath={runningScript.path}
onClose={handleCloseTerminal}
Expand All @@ -118,7 +134,7 @@ export default function Home() {
)}

{activeTab === 'downloaded' && (
<DownloadedScriptsTab />
<DownloadedScriptsTab onInstallScript={handleRunScript} />
)}

{activeTab === 'installed' && (
Expand Down
21 changes: 20 additions & 1 deletion src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@

/* Terminal-specific styles for ANSI escape code rendering */
.terminal-output {
font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
line-height: 1.2;
}

Expand All @@ -142,6 +142,25 @@
background-color: inherit;
}

/* Enhanced terminal styling */
.xterm {
padding: 0.5rem;
}

/* Set basic background - let ANSI colors work naturally */
.xterm .xterm-viewport {
background-color: #0d1117;
}

.xterm .xterm-screen {
background-color: #0d1117;
}

/* Better selection colors */
.xterm .xterm-selection {
background-color: #264f78;
}

/* Mobile-specific improvements */
@media (max-width: 640px) {
/* Improve touch targets */
Expand Down