feat: Refactor App and ServerManager components to improve navigation and modal handling
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 13m26s

This commit is contained in:
2025-07-10 10:02:01 +07:00
parent aaa4878229
commit 9a109a0bf2
2 changed files with 116 additions and 81 deletions
+85 -43
View File
@@ -492,24 +492,12 @@ function ServerManager() {
{/* Delete Modal */}
{showDeleteModal && (
<div className="modal fade show" style={{display: 'block'}} tabIndex="-1">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Подтверждение удаления</h5>
<button type="button" className="btn-close" onClick={() => setShowDeleteModal(false)}></button>
</div>
<div className="modal-body">
<p>Вы уверены, что хотите удалить сервер <strong>{serverToDelete?.ip}</strong>?</p>
<p className="text-muted">Это действие нельзя отменить.</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={() => setShowDeleteModal(false)}>Отмена</button>
<button type="button" className="btn btn-danger" onClick={executeDelete}>Удалить</button>
</div>
</div>
</div>
</div>
<DeleteServerModal
show={showDeleteModal}
server={serverToDelete}
onDelete={executeDelete}
onClose={() => setShowDeleteModal(false)}
/>
)}
{/* Edit Server Modal */}
@@ -527,6 +515,13 @@ function ServerManager() {
// Модальное окно для редактирования сервера с backdrop и анимацией
function EditServerModal({ show, server, onChange, onSave, onClose }) {
const modalRef = useRef(null);
// Локальное состояние для формы
const [localServer, setLocalServer] = useState(server || {});
// Синхронизируем локальное состояние с пропсами
useEffect(() => {
setLocalServer(server || {});
}, [server]);
useEffect(() => {
if (window.Tabler && window.Tabler.Modal && modalRef.current) {
@@ -545,6 +540,12 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {
}
}, [show, onClose]);
const handleChange = (field, value) => {
const updated = { ...localServer, [field]: value };
setLocalServer(updated);
onChange && onChange(updated);
};
return (
<div className="modal" tabIndex="-1" ref={modalRef}>
<div className="modal-dialog">
@@ -554,34 +555,75 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
{server && (
<form onSubmit={e => { e.preventDefault(); onSave(); }}>
<div className="mb-3">
<label className="form-label">IP адрес</label>
<input type="text" className="form-control" value={server.ip} onChange={e => onChange({ ...server, ip: e.target.value })} />
</div>
<div className="mb-3">
<label className="form-label">DNS имя</label>
<input type="text" className="form-control" value={server.dns} onChange={e => onChange({ ...server, dns: e.target.value })} />
</div>
<div className="mb-3">
<label className="form-label">Страна</label>
<input type="text" className="form-control" value={server.country} onChange={e => onChange({ ...server, country: e.target.value })} />
</div>
<div className="mb-3">
<label className="form-label">Провайдер</label>
<input type="text" className="form-control" value={server.provider} onChange={e => onChange({ ...server, provider: e.target.value })} />
</div>
<div className="mb-3">
<label className="form-label">Тип туннеля</label>
<input type="text" className="form-control" value={server.tunnel} onChange={e => onChange({ ...server, tunnel: e.target.value })} />
</div>
</form>
)}
<form onSubmit={e => { e.preventDefault(); onSave && onSave(localServer); }}>
<div className="mb-3">
<label className="form-label">IP адрес</label>
<input type="text" className="form-control" value={localServer.ip || ''} onChange={e => handleChange('ip', e.target.value)} />
</div>
<div className="mb-3">
<label className="form-label">DNS имя</label>
<input type="text" className="form-control" value={localServer.dns || ''} onChange={e => handleChange('dns', e.target.value)} />
</div>
<div className="mb-3">
<label className="form-label">Страна</label>
<input type="text" className="form-control" value={localServer.country || ''} onChange={e => handleChange('country', e.target.value)} />
</div>
<div className="mb-3">
<label className="form-label">Провайдер</label>
<input type="text" className="form-control" value={localServer.provider || ''} onChange={e => handleChange('provider', e.target.value)} />
</div>
<div className="mb-3">
<label className="form-label">Тип туннеля</label>
<input type="text" className="form-control" value={localServer.tunnel || ''} onChange={e => handleChange('tunnel', e.target.value)} />
</div>
</form>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
<button type="button" className="btn btn-primary" onClick={onSave}>Сохранить</button>
<button type="button" className="btn btn-primary" onClick={() => onSave && onSave(localServer)}>Сохранить</button>
</div>
</div>
</div>
</div>
);
}
function DeleteServerModal({ show, server, onDelete, onClose }) {
const modalRef = useRef(null);
useEffect(() => {
if (window.Tabler && window.Tabler.Modal && modalRef.current) {
const modalInstance = window.Tabler.Modal.getOrCreateInstance(modalRef.current);
if (show) {
modalInstance.show();
} else {
modalInstance.hide();
}
const handler = () => onClose && onClose();
modalRef.current.addEventListener('hide.bs.modal', handler);
return () => {
modalRef.current.removeEventListener('hide.bs.modal', handler);
};
}
}, [show, onClose]);
return (
<div className="modal" tabIndex="-1" ref={modalRef}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-status bg-danger"></div>
<div className="modal-header">
<IconAlertTriangle className="icon text-danger me-2" size={28} />
<h5 className="modal-title">Подтверждение удаления</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<p>Вы уверены, что хотите удалить сервер <strong>{server?.ip}</strong>?</p>
<p className="text-muted">Это действие нельзя отменить.</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
<button type="button" className="btn btn-danger" onClick={onDelete}>Удалить</button>
</div>
</div>
</div>