Files
ProxmoxVE-Local/src/app/_components/ExecutionModeModal.tsx
Michel Roegl-Brunner d932f5a499 feat: comprehensive mobile responsiveness improvements (#76)
* feat: comprehensive mobile responsiveness improvements

- Made main layout responsive with proper mobile padding and spacing
- Updated Terminal component with mobile-friendly controls and sizing
- Enhanced VersionDisplay with responsive layout and condensed mobile text
- Improved ScriptsGrid and DownloadedScriptsTab with mobile-first design
- Made CategorySidebar responsive with horizontal scroll on mobile
- Fixed FilterBar styling consistency and added Lucide icons
- Enhanced all modals (Settings, ScriptDetail, ExecutionMode, etc.) for mobile
- Updated ServerForm and ServerList with mobile-optimized layouts
- Added global CSS improvements for mobile touch targets and typography
- Fixed close button placement in ScriptDetailModal to follow UI conventions
- Implemented responsive breakpoints throughout the application
- Added proper viewport meta tag for mobile rendering

All components now provide excellent user experience across all device sizes.

* fix: improve mobile terminal input handling for SSH processes

- Updated mobile input controls to use up/down arrows instead of numbered buttons
- Fixed WebSocket input handling to support both regular processes and pty processes (SSH)
- Added comprehensive debugging logs for input handling
- Added visual feedback showing when inputs are sent
- Improved error handling and user feedback for input failures

The mobile terminal input should now work properly with SSH-executed scripts.

* debug: add comprehensive debugging for mobile terminal input

- Added byte-level debugging to see exact input being sent
- Added test button to verify basic input works
- Enhanced server-side logging to track input processing
- Improved escape sequence handling for arrow keys

This will help identify why mobile inputs aren't working while keyboard works.

* debug: add comprehensive server-side debugging for mobile input

- Added detailed logging for mobile input processing
- Added confirmation messages sent back to client
- Enhanced debugging to track input flow from client to server
- Added JSON string representation of inputs for better debugging

This will help identify why mobile inputs aren't working while keyboard works.

* debug: add WebSocket message routing debugging

- Added comprehensive logging for all WebSocket messages
- Added specific debugging for input action handling
- Added full message object logging to identify routing issues
- Enhanced input action validation logging

This will help identify if input messages are reaching the server at all.

* debug: add comprehensive client-side debugging for mobile input

- Added detailed logging for button click events
- Added WebSocket connection state debugging
- Added message sending confirmation logging
- Enhanced sendInput function with complete debugging

This will help identify if mobile buttons are being clicked and if WebSocket messages are being sent.

* debug: add WebSocket connection tracking and message debugging

- Added connection ID tracking for each WebSocket connection
- Added detailed logging for all incoming WebSocket messages
- Added connection close and error event logging
- Enhanced message parsing debugging

This will help identify if mobile input messages are reaching the server and which connection they're using.

* fix: correct WebSocket message format for keyboard input

- Fixed keyboard input to use 'data' field instead of 'input' field
- Added debugging for keyboard input to compare with mobile input
- Both mobile and keyboard inputs now use consistent message format
- This should fix the issue where mobile inputs weren't working

The server expects 'data' field but keyboard was sending 'input' field.

* debug: add WebSocket connection details for mobile vs keyboard input

- Added WebSocket URL and protocol logging for both mobile and keyboard input
- Added WebSocket object logging to compare connections
- Enhanced debugging to identify if mobile and keyboard use different WebSocket connections

This will help identify if there's a connection mismatch between mobile and keyboard input.

* fix: correct WebSocket message format to use 'input' field

- Reverted both mobile and keyboard input to use 'input' field instead of 'data'
- Updated server to expect 'input' field in WebSocket messages
- Fixed server-side logging to use correct field names
- This should restore both keyboard and mobile input functionality

The server was actually expecting 'input' field, not 'data' field.

* feat: add left/right arrow buttons to mobile terminal input

- Added ChevronLeft and ChevronRight icons to imports
- Added left/right navigation buttons alongside up/down buttons
- Left button sends \x1b[D (ANSI escape sequence for left arrow)
- Right button sends \x1b[C (ANSI escape sequence for right arrow)
- Updated visual feedback to show 'Left' and 'Right' for arrow inputs
- Mobile users now have full directional navigation: up, down, left, right

This completes the mobile terminal navigation controls for touch devices.

* feat: add spacebar button and clean up mobile terminal controls

- Added spacebar button to mobile input controls
- Removed 'Yes (y)' and 'Test (1)' buttons to simplify interface
- Changed action buttons from 3-column to 2-column grid (Enter, Space)
- Updated visual feedback to show 'Space' for spacebar input
- Mobile controls now focus on essential navigation and input

This streamlines the mobile terminal interface with only the most useful controls.

* feat: add backspace button to mobile terminal controls

- Added backspace button (⌫ Backspace) to action buttons
- Sends \b character for backspace functionality
- Changed action buttons from 2-column to 3-column grid
- Updated visual feedback to show 'Backspace' for backspace input
- Mobile users now have complete text editing capabilities

This completes the essential mobile terminal input controls with navigation, text input, and editing functions.

* feat: improve mobile terminal scaling and responsiveness

- Reduced font size from 14px to 10px on mobile devices (< 768px width)
- Set mobile-specific terminal dimensions (20 rows, 60 cols) for better fit
- Reduced mobile terminal height from 20rem to 16rem (256px min-height)
- Added responsive resize listener to adjust terminal size on orientation changes
- Improved mobile terminal display to prevent cramped text and odd appearance
- Better balance between terminal content and mobile input controls

This makes the terminal much more readable and usable on mobile devices.

* fix: improve ANSI escape sequence handling for whiptail dialogs

- Added better ANSI handling configuration to terminal
- Added detection and logging for screen clearing sequences (\x1b[2J, \x1b[H\x1b[2J)
- Added detection and logging for cursor positioning sequences
- Enabled allowProposedApi for better terminal compatibility
- Added debugging to identify when clear screen operations occur

This should fix the issue where whiptail dialogs duplicate content and don't properly clear the screen on mobile input.

* debug: add whiptail/dialog detection and logging

- Added detection for whiptail and dialog output in terminal messages
- Added logging to track when whiptail content is being processed
- This will help identify if the issue is with ANSI sequence processing
- Console logs will show when clear screen, cursor positioning, and whiptail content is detected

This debugging will help identify the root cause of the terminal rerendering issue.

* fix: force screen clear on cursor positioning to prevent whiptail duplication

- Modified output handling to force screen clear (\x1b[2J\x1b[H) when cursor positioning is detected
- Removed whiptail-specific detection in favor of broader cursor positioning approach
- This should prevent content duplication when whiptail redraws its interface
- Cursor positioning sequences often indicate a full screen redraw is intended

This aggressive approach should finally fix the terminal rerendering issue.

* debug: add comprehensive output debugging and try terminal.clear()

- Added detailed logging for all output messages including length, preview, and ANSI detection
- Changed cursor positioning handling to use xtermRef.current.clear() for more aggressive clearing
- This will help identify exactly what data is being received and how it's being processed
- The terminal.clear() method should completely reset the terminal buffer

This debugging will help us understand why the duplication is still occurring.

* debug: add whiptail session detection and enhanced debugging

- Added inWhiptailSession state to track when we're in a whiptail dialog
- Added detection for whiptail/dialog content to set session flag
- Enhanced output debugging with comprehensive logging
- Added aggressive terminal clearing specifically for whiptail sessions
- Reset whiptail session when script ends
- Set explicit terminal dimensions (cols/rows) for better behavior

This should provide much more detailed debugging information and better handling of whiptail sessions.

* feat: improve whiptail centering on mobile devices

- Reduced mobile terminal dimensions to 50 cols x 18 rows for better whiptail centering
- Reduced mobile terminal height from 16rem to 14rem (224px min-height)
- Added isMobile state to component level for consistent mobile detection
- Added horizontal padding on mobile to help center terminal content
- Smaller terminal dimensions should help whiptail dialogs appear more centered

This should improve the visual positioning of whiptail dialogs on mobile devices.

* feat: improve whiptail horizontal centering on mobile

- Reduced mobile terminal dimensions to 40 cols x 16 rows for better centering
- Added mobile-terminal CSS class with flex centering
- Added CSS rules to center xterm content horizontally on mobile
- Added transform translateX for fine-tuning horizontal position
- Increased horizontal padding to 2rem on mobile

This should better center the whiptail dialog horizontally on mobile devices.

* fix: resolve text wrapping and overflow issues in mobile terminal

- Increased mobile terminal dimensions to 60 cols x 20 rows to prevent text cutoff
- Increased mobile terminal height back to 16rem (256px) for better content display
- Added overflow: hidden to mobile terminal CSS to prevent content overflow
- Added width and max-width constraints to xterm elements
- Reduced horizontal padding and transform to better fit content
- Cleaned up duplicate terminal configuration options

This should fix the weird text wrapping and cutoff issues on mobile devices.

* fix: try auto-fit approach to resolve mobile terminal text wrapping

- Removed fixed terminal dimensions on mobile to let it auto-fit
- Added double fit calls for mobile to ensure proper sizing
- Removed restrictive CSS overflow and transform rules
- Simplified terminal container styling for better auto-fitting
- Let xterm.js handle the sizing automatically on mobile

This approach should allow the terminal to properly fit the content without text cutoff.

* fix: improve mobile terminal centering with specific dimensions

- Set mobile terminal to 45 cols x 18 rows for better whiptail dialog fit
- Added padding and transform to better center content on mobile
- Used flex centering in terminal container for mobile
- Added overflow hidden to prevent text cutoff
- More aggressive centering approach for mobile devices

This should better center the whiptail dialog and prevent text cutoff on mobile.

* feat: implement virtual terminal overflow approach for mobile whiptail

- Increased mobile virtual terminal to 80 cols x 30 rows (larger than display)
- Let virtual terminal overflow and center the whiptail dialog in viewport
- Added overflow: hidden to container to hide overflow content
- Centered viewport to show middle portion of virtual terminal
- This approach lets whiptail render at full size while showing only the center

This should properly center the whiptail dialog without text wrapping or cutoff issues.

* revert: simplify mobile terminal approach and reduce font size

- Reverted to simpler 50 cols x 20 rows terminal dimensions
- Reduced mobile font size from 10px to 8px for better fit
- Simplified CSS to basic flex centering without complex overflow handling
- Added multiple fit calls for mobile to ensure proper terminal sizing
- Removed complex virtual terminal overflow approach that wasn't working

This should provide a more stable and predictable mobile terminal display.

* feat: reduce mobile terminal font size and dimensions for better fit

- Reduced mobile font size from 8px to 6px for even smaller text
- Reduced mobile terminal dimensions to 45 cols x 18 rows
- This should provide more room for whiptail dialog content on mobile
- Smaller font and dimensions should prevent text cutoff and wrapping

This should finally get the whiptail dialog to fit properly on mobile devices.

* feat: increase mobile font size and fix whiptail duplication

- Increased mobile font size from 6px to 7px for slightly larger text
- Fixed whiptail duplication by adding delay after terminal clear
- Added setTimeout to ensure clear is processed before writing new content
- This should prevent the weird lines/duplication while keeping good fit

This should give a good balance between readability and fit while preventing duplication.

* fix: implement more aggressive terminal clearing for whiptail

- Added multiple clear operations: clear(), \x1b[2J\x1b[H, \x1b[3J, \x1b[2J
- Added scrollback buffer clearing with \x1b[3J
- Increased delay from 10ms to 50ms for better processing
- Added double clear() calls to force terminal buffer clearing
- This should finally eliminate the duplication lines in whiptail dialogs

This aggressive approach should completely clear the terminal before redrawing whiptail content.

* fix: implement terminal reset approach for whiptail duplication

- Added immediate clearing when whiptail session is detected
- Implemented terminal.reset() method for complete terminal state reset
- Added longer 100ms delay after reset to ensure proper processing
- Clear terminal immediately when whiptail content is first detected
- This nuclear approach should completely eliminate duplication issues

This should finally solve the persistent duplication problem by completely resetting the terminal state.

* cleanup: remove all debug logging from terminal component

- Removed all console.log statements from output handling
- Removed debug logging from mobile input functions
- Removed debug logging from keyboard input handler
- Removed debug logging from all mobile button click handlers
- Simplified button onClick handlers to direct function calls
- Kept all functionality while removing debugging noise

The terminal now has clean, production-ready code without debug output.

* feat: make InstalledScriptsTab mobile-friendly with responsive layout

- Created ScriptInstallationCard component for mobile view
- Added responsive layout: cards on mobile (< md), table on desktop (>= md)
- Made filters section mobile-friendly with stacked layout
- Improved add script form with responsive button layout
- Cards show all script details in a clean, touch-friendly format
- Maintained all existing functionality (edit, update, delete)
- Used proper Tailwind breakpoints for seamless responsive behavior

The installed scripts tab now provides an optimal experience on both mobile and desktop devices.

* fix: resolve React hooks dependency warnings in Terminal component

- Added missing 'inWhiptailSession' dependency to useCallback
- Fixed ref cleanup issue by storing terminalRef.current in variable
- Added missing 'isMobile' dependency to useEffect
- Improved nullish coalescing in ScriptInstallationCard (|| to ??)
- All React hooks warnings resolved, build passes cleanly

The Terminal component now follows React best practices for hooks dependencies.
2025-10-08 13:56:20 +02:00

209 lines
8.0 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import type { Server } from '../../types/server';
import { Button } from './ui/button';
interface ExecutionModeModalProps {
isOpen: boolean;
onClose: () => void;
onExecute: (mode: 'local' | 'ssh', server?: Server) => void;
scriptName: string;
}
export function ExecutionModeModal({ isOpen, onClose, onExecute, scriptName }: ExecutionModeModalProps) {
const [servers, setServers] = useState<Server[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [selectedMode, setSelectedMode] = useState<'local' | 'ssh'>('local');
const [selectedServer, setSelectedServer] = useState<Server | null>(null);
useEffect(() => {
if (isOpen) {
void fetchServers();
}
}, [isOpen]);
const fetchServers = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch('/api/servers');
if (!response.ok) {
throw new Error('Failed to fetch servers');
}
const data = await response.json();
setServers(data as Server[]);
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
} finally {
setLoading(false);
}
};
const handleExecute = () => {
if (selectedMode === 'ssh' && !selectedServer) {
setError('Please select a server for SSH execution');
return;
}
onExecute(selectedMode, selectedServer ?? undefined);
onClose();
};
const handleModeChange = (mode: 'local' | 'ssh') => {
setSelectedMode(mode);
if (mode === 'local') {
setSelectedServer(null);
}
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 backdrop-blur-sm bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-card rounded-lg shadow-xl max-w-md w-full border border-border">
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-border">
<h2 className="text-xl font-bold text-foreground">Execution Mode</h2>
<Button
onClick={onClose}
variant="ghost"
size="icon"
className="text-muted-foreground hover:text-foreground"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</Button>
</div>
{/* Content */}
<div className="p-6">
<div className="mb-6">
<h3 className="text-lg font-medium text-foreground mb-2">
Where would you like to execute &quot;{scriptName}&quot;?
</h3>
</div>
{error && (
<div className="mb-4 p-3 bg-destructive/10 border border-destructive/20 rounded-md">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-destructive" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm text-destructive">{error}</p>
</div>
</div>
</div>
)}
{/* Execution Mode Selection */}
<div className="space-y-4 mb-6">
{/* SSH Execution */}
<div
className={`border rounded-lg p-4 cursor-pointer transition-colors ${
selectedMode === 'ssh'
? 'border-primary bg-primary/10'
: 'border-border hover:border-primary/50'
}`}
onClick={() => handleModeChange('ssh')}
>
<div className="flex items-center">
<input
type="radio"
id="ssh"
name="executionMode"
value="ssh"
checked={selectedMode === 'ssh'}
onChange={() => handleModeChange('ssh')}
className="h-4 w-4 text-primary focus:ring-primary border-border"
/>
<label htmlFor="ssh" className="ml-3 flex-1 cursor-pointer">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-10 h-10 bg-primary/10 rounded-full flex items-center justify-center">
<svg className="w-6 h-6 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
</div>
<div className="ml-3">
<h4 className="text-sm font-medium text-foreground">SSH Execution</h4>
<p className="text-sm text-muted-foreground">Run the script on a remote server</p>
</div>
</div>
</label>
</div>
</div>
</div>
{/* Server Selection (only for SSH mode) */}
{selectedMode === 'ssh' && (
<div className="mb-6">
<label htmlFor="server" className="block text-sm font-medium text-foreground mb-2">
Select Server
</label>
{loading ? (
<div className="text-center py-4">
<div className="inline-block animate-spin rounded-full h-6 w-6 border-b-2 border-primary"></div>
<p className="mt-2 text-sm text-muted-foreground">Loading servers...</p>
</div>
) : servers.length === 0 ? (
<div className="text-center py-4 text-muted-foreground">
<p className="text-sm">No servers configured</p>
<p className="text-xs mt-1">Add servers in Settings to use SSH execution</p>
</div>
) : (
<select
id="server"
value={selectedServer?.id ?? ''}
onChange={(e) => {
const serverId = parseInt(e.target.value);
const server = servers.find(s => s.id === serverId);
setSelectedServer(server ?? null);
}}
className="w-full px-3 py-2 border border-input rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary bg-background text-foreground"
>
<option value="">Select a server...</option>
{servers.map((server) => (
<option key={server.id} value={server.id}>
{server.name} ({server.ip}) - {server.user}
</option>
))}
</select>
)}
</div>
)}
{/* Action Buttons */}
<div className="flex justify-end space-x-3">
<Button
onClick={onClose}
variant="outline"
size="default"
>
Cancel
</Button>
<Button
onClick={handleExecute}
disabled={selectedMode === 'ssh' && !selectedServer}
variant="default"
size="default"
className={selectedMode === 'ssh' && !selectedServer ? 'bg-gray-400 cursor-not-allowed' : ''}
>
{selectedMode === 'local' ? 'Run Locally' : 'Run on Server'}
</Button>
</div>
</div>
</div>
</div>
);
}