import React, { useState, useEffect } from 'react'; import { Box, Play, Square, Terminal as TerminalIcon, MoreHorizontal, RefreshCw, RotateCw, FileText, Search, X, Loader2 } from 'lucide-react'; import TerminalComponent from '../components/TerminalComponent'; const API_DOCKER_CONTAINERS = '/api/docker/containers'; const formatBytes = (bytes, decimals = 2) => { if (!+bytes) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`; }; const DockerManager = () => { const [containers, setContainers] = useState([]); // ... (rest of state items are same) const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [activeTerminal, setActiveTerminal] = useState(null); // containerId const [searchQuery, setSearchQuery] = useState(''); const [showLogs, setShowLogs] = useState(null); // containerId const [logsContent, setLogsContent] = useState(''); const [actionLoading, setActionLoading] = useState(null); // containerId being acted upon const fetchContainers = async () => { setLoading(true); try { const response = await fetch(API_DOCKER_CONTAINERS); if (!response.ok) throw new Error('Failed to fetch containers'); const data = await response.json(); setContainers(data); setError(null); } catch (err) { console.error(err); setError('Could not load Docker containers.'); } finally { setLoading(false); } }; // ... (rest of useEffect and handlers existing) useEffect(() => { fetchContainers(); // Poll for updates every 5 seconds to keep stats fresh const interval = setInterval(fetchContainers, 5000); return () => clearInterval(interval); }, []); // Docker Actions const handleContainerAction = async (id, action) => { setActionLoading(id); try { const response = await fetch(`/api/docker/containers/${id}/${action}`, { method: 'POST' }); if (!response.ok) throw new Error(`Failed to ${action} container`); await fetchContainers(); // Refresh list } catch (err) { alert(err.message); } finally { setActionLoading(null); } }; const handleFetchLogs = async (id) => { setLogsContent('Loading logs...'); setShowLogs(id); try { const response = await fetch(`/api/docker/containers/${id}/logs`); if (!response.ok) throw new Error('Failed to fetch logs'); const data = await response.text(); setLogsContent(data); } catch (err) { setLogsContent(`Error: ${err.message}`); } }; return (
{/* ... (header code) */}

도커 컨테이너

{!activeTerminal && (
setSearchQuery(e.target.value)} style={{ padding: '0.5rem 1rem 0.5rem 2.2rem', borderRadius: '8px', border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(255,255,255,0.05)', color: 'inherit', outline: 'none', width: '200px', fontSize: '0.9rem' }} />
)}
{error && (
{error}
)} {/* Terminal View */} {activeTerminal ? (
터미널 - {containers.find(c => c.Id === activeTerminal)?.Names[0] || activeTerminal}
) : (
{loading && containers.length === 0 ? (
) : containers .filter(c => c.Names[0].toLowerCase().includes(searchQuery.toLowerCase()) || c.Image.toLowerCase().includes(searchQuery.toLowerCase()) ) .map(container => (

{container.Names[0].replace(/^\//, '')}

이미지: {container.Image.length > 20 ? container.Image.substring(0, 20) + '...' : container.Image}
상태: {container.State}
{/* Stats Display */} {container.stats && container.State === 'running' && ( <>
CPU: {container.stats.cpu.toFixed(2)}%
Memory: {formatBytes(container.stats.memory)}
)}
{/* Action Buttons */}
{container.State === 'running' ? ( <> ) : ( )}
))}
)} {/* Logs Modal */} {showLogs && (

로그

                            {logsContent}
                        
)}
); }; export default DockerManager;