Files
ProxmoxVE-Local/src/app/_components/ErrorModal.tsx
Michel Roegl-Brunner 5b45293b4d feat: Add LXC Container Control Features (#124)
* feat: Add LXC container control functionality to Installed Scripts page

- Add reusable ConfirmationModal component with simple and type-to-confirm variants
- Add three new tRPC endpoints for container control:
  - getContainerStatus: Check container running/stopped state via pct status
  - controlContainer: Start/stop containers via pct start/stop commands
  - destroyContainer: Destroy containers via pct destroy and delete DB records
- Enhance InstalledScriptsTab with container status management and confirmation flows
- Update ScriptInstallationCard with Start/Stop and Destroy buttons for SSH scripts
- Add container control buttons to desktop table view with proper status handling
- Update help documentation with comprehensive container control feature guide
- Implement safety features:
  - Simple OK/Cancel confirmation for start/stop actions
  - Type-to-confirm modal requiring container ID for destroy actions
  - SSH connection validation and error handling
  - Loading states and user feedback for all operations
- Only show control buttons for SSH scripts with valid container IDs
- Maintain backward compatibility with existing delete functionality for non-SSH scripts

All container control operations execute via SSH using existing infrastructure.
Real-time container status checking and caching for optimal performance.

* fix: Resolve linting errors in LXC control functionality

- Remove unused getStatusMutation variable
- Fix floating promises by adding void operator
- Add missing dependencies to useEffect hooks
- Fix unsafe argument types by casting server IDs to Number
- Remove unused commandOutput variables
- Use useCallback for fetchContainerStatus to fix dependency issues
- Move function definition before usage to resolve hoisting errors

* fix: Add missing execution_mode property to InstalledScript interface in ScriptInstallationCard

- Add execution_mode: local | ssh property to InstalledScript interface
- Fixes TypeScript build error when checking script.execution_mode === ssh
- Ensures type consistency across all components

* fix: Resolve status detection conflicts by using unified bulk fetching

- Remove individual fetchContainerStatus function that was conflicting with bulk fetching
- Update controlContainerMutation to use fetchContainerStatuses instead of individual calls
- Remove unused utils variable to clean up linting warnings
- Simplify status detection to use only the bulk getContainerStatuses endpoint
- This should resolve the status detection issues by eliminating competing fetch mechanisms

* fix: Stop infinite API call loops that were overwhelming the server

- Remove fetchContainerStatuses from useEffect dependencies to prevent infinite loops
- Use useRef to access current scripts without causing dependency cycles
- Reduce multiple useEffect hooks that were all triggering status checks
- This should stop the 30+ simultaneous API calls that were redlining the server
- Status checks now happen only when needed: on load, after operations, and every 60s

* feat: Implement efficient pct list approach for container status checking

- Replace individual container status checks with bulk pct list per server
- Update getContainerStatuses to run pct list once per server and parse all results
- Simplify frontend to just pass server IDs instead of individual container data
- Much more efficient: 1 SSH call per server instead of 1 call per container
- Parse pct list output format: CTID Status Name
- Map pct list status (running/stopped) to our status format
- This should resolve the server overload issues while maintaining functionality

* fix: Remove duplicate container status display from STATUS column

- Remove container runtime status from STATUS column in both desktop and mobile views
- Keep container status display next to container ID where it belongs
- STATUS column now only shows installation status (SUCCESS/FAILED)
- Container runtime status (running/stopped) remains next to container ID
- Cleaner UI with no duplicate status information

* feat: Trigger status check when switching to installed scripts tab

- Add useEffect hook that triggers fetchContainerStatuses when component mounts
- This ensures container statuses are refreshed every time user switches to the tab
- Improves user experience by always showing current container states
- Uses empty dependency array to run only once per tab switch

* cleanup: Remove all console.log statements from codebase

- Remove console.log statements from InstalledScriptsTab.tsx
- Remove console.log statements from installedScripts.ts router
- Remove console.log statements from VersionDisplay.tsx
- Remove console.log statements from ScriptsGrid.tsx
- Keep console.error statements for proper error logging
- Cleaner production logs without debug output

* feat: Display detailed SSH error messages for container operations

- Capture both stdout and stderr from pct start/stop/destroy commands
- Show actual SSH error output to users instead of generic error messages
- Update controlContainer and destroyContainer to return detailed error messages
- Improve frontend error handling to display backend error messages
- Users now see specific error details like permission denied, container not found, etc.
- Better debugging experience with meaningful error feedback

* feat: Auto-stop containers before destroy and improve error UI

- Automatically stop running containers before destroying them
- Create custom ErrorModal component to replace ugly browser alerts
- Support both error and success modal types with appropriate styling
- Show detailed SSH error messages in a beautiful modal interface
- Update destroy success message to indicate if container was stopped first
- Better UX with consistent design language and proper error handling
- Auto-close modals after 10 seconds for better user experience

* fix: Replace dialog component with custom modal implementation

- Remove dependency on non-existent dialog component
- Use same modal pattern as ConfirmationModal for consistency
- Custom modal with backdrop, proper styling, and responsive design
- Maintains all functionality while fixing module resolution error
- Consistent with existing codebase patterns

* feat: Add instant success feedback for container start/stop operations

- Show success modal immediately after start/stop operations
- Update container status in UI instantly before background status check
- Prevents user confusion by showing expected status change immediately
- Add containerId to backend response for proper script identification
- Success modals show appropriate messages for start vs stop operations
- Background status check still runs to ensure accuracy
- Better UX with instant visual feedback

* fix: Improve Container Control section styling in help modal

- Replace bright red styling with subtle accent colors
- Use consistent design language that matches the rest of the interface
- Change safety features from red to yellow warning styling
- Better visual hierarchy and readability
- Maintains warning importance while being less jarring

* fix: Make safety features section much more subtle in help modal

- Replace bright yellow with muted background colors
- Use standard text colors (text-foreground, text-muted-foreground)
- Maintains warning icon but with consistent styling
- Much less jarring against dark theme
- Better integration with overall design language

* feat: Replace update script alerts with custom confirmation modal

- Replace browser alert() with custom ErrorModal for validation errors
- Replace browser confirm() with custom ConfirmationModal for update confirmation
- Add type-to-confirm safety feature requiring container ID input
- Include data loss warning and backup recommendation in confirmation message
- Consistent UI/UX with other confirmation dialogs
- Better error messaging with detailed information

* fix: Resolve all build errors and warnings

- Fix nullish coalescing operator warnings (|| to ??)
- Remove unused imports and variables
- Fix TypeScript type errors with proper casting
- Update ConfirmationModal state type to include missing properties
- Fix useEffect dependency warnings
- All build errors resolved, only minor unused variable warning remains
- Build now passes successfully

* feat: Disable update button when container is stopped

- Add disabled condition to update button in table view
- Add disabled condition to update button in mobile card view
- Prevents users from updating stopped containers
- Uses containerStatus to determine if button should be disabled
- Improves UX by preventing invalid operations on stopped containers

* fix: Resolve infinite loop in status updates

- Remove containerStatusMutation from fetchContainerStatuses dependencies
- Use empty dependency array for fetchContainerStatuses useCallback
- Remove fetchContainerStatuses from useEffect dependencies
- Only depend on scripts.length to prevent infinite loops
- Status updates now run only when scripts change, not on every render

* fix: Correct misleading text in update confirmation modal

- Change "will re-run the script installation process" to "will update the script"
- More accurate description of what the update operation actually does
- Maintains warning about potential container impact and backup recommendation
- Better user understanding of the actual operation being performed

* refactor: Remove all comments from InstalledScriptsTab.tsx

- Remove all single-line comments (//)
- Remove all multi-line comments (/* */)
- Clean up excessive empty lines
- Improve code readability and reduce file size
- Maintain all functionality while removing documentation comments

* refactor: Improve code organization and add comprehensive comments

- Add clear section comments for better code organization
- Document all major state variables and their purposes
- Add detailed comments for complex logic and operations
- Improve readability with better spacing and structure
- Maintain all existing functionality while improving maintainability
- Add comments for container control, mutations, and UI sections
2025-10-13 16:36:11 +02:00

88 lines
2.6 KiB
TypeScript

'use client';
import { useEffect } from 'react';
import { Button } from './ui/button';
import { AlertCircle, CheckCircle } from 'lucide-react';
interface ErrorModalProps {
isOpen: boolean;
onClose: () => void;
title: string;
message: string;
details?: string;
type?: 'error' | 'success';
}
export function ErrorModal({
isOpen,
onClose,
title,
message,
details,
type = 'error'
}: ErrorModalProps) {
// Auto-close after 10 seconds
useEffect(() => {
if (isOpen) {
const timer = setTimeout(() => {
onClose();
}, 10000);
return () => clearTimeout(timer);
}
}, [isOpen, onClose]);
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-lg w-full border border-border">
{/* Header */}
<div className="flex items-center justify-center p-6 border-b border-border">
<div className="flex items-center gap-3">
{type === 'success' ? (
<CheckCircle className="h-8 w-8 text-green-600 dark:text-green-400" />
) : (
<AlertCircle className="h-8 w-8 text-red-600 dark:text-red-400" />
)}
<h2 className="text-xl font-semibold text-foreground">{title}</h2>
</div>
</div>
{/* Content */}
<div className="p-6">
<p className="text-sm text-foreground mb-4">{message}</p>
{details && (
<div className={`rounded-lg p-3 ${
type === 'success'
? 'bg-green-50 dark:bg-green-950/20 border border-green-200 dark:border-green-800'
: 'bg-red-50 dark:bg-red-950/20 border border-red-200 dark:border-red-800'
}`}>
<p className={`text-xs font-medium mb-1 ${
type === 'success'
? 'text-green-800 dark:text-green-200'
: 'text-red-800 dark:text-red-200'
}`}>
{type === 'success' ? 'Details:' : 'Error Details:'}
</p>
<pre className={`text-xs whitespace-pre-wrap break-words ${
type === 'success'
? 'text-green-700 dark:text-green-300'
: 'text-red-700 dark:text-red-300'
}`}>
{details}
</pre>
</div>
)}
</div>
{/* Footer */}
<div className="flex justify-end gap-3 p-6 border-t border-border">
<Button variant="outline" onClick={onClose}>
Close
</Button>
</div>
</div>
</div>
);
}