Initial commit
This commit is contained in:
90
frontend/src/components/Console.jsx
Normal file
90
frontend/src/components/Console.jsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { Send } from 'lucide-react';
|
||||
import axios from 'axios';
|
||||
import { API_URL, WS_URL } from '../config';
|
||||
|
||||
export default function Console({ serverName, token, theme }) {
|
||||
const [logs, setLogs] = useState([]);
|
||||
const [command, setCommand] = useState('');
|
||||
const logsEndRef = useRef(null);
|
||||
const wsRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
setLogs([]);
|
||||
|
||||
const ws = new WebSocket(`${WS_URL}/ws/servers/${serverName}/console`);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket подключен');
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
setLogs((prev) => [...prev, event.data]);
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket ошибка:', error);
|
||||
};
|
||||
|
||||
wsRef.current = ws;
|
||||
|
||||
return () => {
|
||||
ws.close();
|
||||
};
|
||||
}, [serverName]);
|
||||
|
||||
useEffect(() => {
|
||||
logsEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, [logs]);
|
||||
|
||||
const sendCommand = async (e) => {
|
||||
e.preventDefault();
|
||||
if (!command.trim()) return;
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
`${API_URL}/api/servers/${serverName}/command`,
|
||||
{ command: command.trim() },
|
||||
{ headers: { Authorization: `Bearer ${token}` } }
|
||||
);
|
||||
setCommand('');
|
||||
} catch (error) {
|
||||
console.error('Ошибка отправки команды:', error);
|
||||
alert(error.response?.data?.detail || 'Ошибка отправки команды');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col h-full ${theme.primary}`}>
|
||||
<div className={`flex-1 overflow-y-auto p-4 font-mono text-sm ${theme.secondary}`}>
|
||||
{logs.length === 0 ? (
|
||||
<div className={theme.textSecondary}>Консоль пуста. Запустите сервер для просмотра логов.</div>
|
||||
) : (
|
||||
logs.map((log, index) => (
|
||||
<div key={index} className={`${theme.text} whitespace-pre-wrap leading-relaxed`}>
|
||||
{log}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
<div ref={logsEndRef} />
|
||||
</div>
|
||||
|
||||
<form onSubmit={sendCommand} className={`${theme.border} border-t p-4 flex gap-2`}>
|
||||
<input
|
||||
type="text"
|
||||
value={command}
|
||||
onChange={(e) => setCommand(e.target.value)}
|
||||
placeholder="Введите команду..."
|
||||
className={`flex-1 ${theme.input} ${theme.border} border rounded-xl px-4 py-2 ${theme.text} focus:outline-none focus:ring-2 focus:ring-blue-500 transition`}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className={`${theme.accent} ${theme.accentHover} px-6 py-2 rounded-xl flex items-center gap-2 text-white transition`}
|
||||
>
|
||||
<Send className="w-4 h-4" />
|
||||
Отправить
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user