import { useState, useEffect, useRef } from 'react'; import { IconPlus } from '@tabler/icons-react'; import { makeGateway, normalizeGateways, needsGateways as NEEDS_GATEWAYS, SERVER_TYPE_OPTIONS } from '../../utils/serverUtils.js'; /** * Модальное окно для редактирования сервера */ function EditServerModal({ show, server, onChange, onSave, onClose }) { const modalRef = useRef(null); const initializedRef = useRef(false); const [localServer, setLocalServer] = useState({}); const ensureGateways = (srv) => { if (!srv) return { gateways: [] }; const needs = NEEDS_GATEWAYS(srv.type); let gateways = []; if (needs) { gateways = normalizeGateways(srv.gateways, srv.gateway || srv.dns || srv.ip); if (gateways.length === 0) { gateways = [makeGateway({ primary: true })]; } } return { ...srv, gateways }; }; useEffect(() => { if (show && server && !initializedRef.current) { const prepared = ensureGateways(server); setLocalServer(prepared); initializedRef.current = true; } if (!show) { initializedRef.current = false; } }, [show, server]); 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 () => { if (modalRef.current) { modalRef.current.removeEventListener('hide.bs.modal', handler); } }; } }, [show, onClose]); const handleFieldChange = (field, value) => { setLocalServer(prev => { const updated = { ...prev, [field]: value }; onChange && onChange(updated); return updated; }); }; const handleGatewayChange = (idx, field, value) => { setLocalServer(prev => { const currentGateways = Array.isArray(prev.gateways) ? prev.gateways : []; const updatedGateways = currentGateways.map((gw, i) => i === idx ? { ...gw, [field]: value } : gw ); const updated = { ...prev, gateways: updatedGateways }; onChange && onChange(updated); return updated; }); }; const handlePrimaryChange = (idx, checked) => { setLocalServer(prev => { const currentGateways = Array.isArray(prev.gateways) ? prev.gateways : []; const updatedGateways = currentGateways.map((gw, i) => ({ ...gw, primary: i === idx ? checked : false })); if (!updatedGateways.some(g => g.primary) && updatedGateways.length > 0) { updatedGateways[idx].primary = true; } const updated = { ...prev, gateways: updatedGateways }; onChange && onChange(updated); return updated; }); }; const handleAddGateway = () => { setLocalServer(prev => { const currentGateways = Array.isArray(prev.gateways) ? prev.gateways : []; const newGw = makeGateway({ primary: currentGateways.length === 0 }); const updatedGateways = [...currentGateways, newGw]; const updated = { ...prev, gateways: updatedGateways }; onChange && onChange(updated); return updated; }); }; const handleRemoveGateway = (idx) => { setLocalServer(prev => { const currentGateways = Array.isArray(prev.gateways) ? prev.gateways : []; if (currentGateways.length <= 1) return prev; const updatedGateways = currentGateways.filter((_, i) => i !== idx); if (!updatedGateways.some(g => g.primary) && updatedGateways.length > 0) { updatedGateways[0].primary = true; } const updated = { ...prev, gateways: updatedGateways }; onChange && onChange(updated); return updated; }); }; const currentGateways = Array.isArray(localServer.gateways) ? localServer.gateways : []; const showGateways = NEEDS_GATEWAYS(localServer.type); return (
Редактировать сервер
{ e.preventDefault(); onSave && onSave(localServer); }}>
handleFieldChange('id', e.target.value)} placeholder="srv-1" />
handleFieldChange('ip', e.target.value)} />
handleFieldChange('extIp', e.target.value)} placeholder="публичный IP, если отличается" />
handleFieldChange('internalIp', e.target.value)} placeholder="10.x.x.x / 192.168.x.x" />
handleFieldChange('dns', e.target.value)} />
handleFieldChange('country', e.target.value)} />
handleFieldChange('provider', e.target.value)} />
handleFieldChange('tunnel', e.target.value)} />
{showGateways && ( <>
Шлюзы ({currentGateways.length})
{currentGateways.map((gw, idx) => (
handleGatewayChange(idx, 'name', e.target.value)} placeholder="GW-MSK" required />
handleGatewayChange(idx, 'ip', e.target.value)} placeholder="10.0.0.1" />
handleGatewayChange(idx, 'comment', e.target.value)} placeholder="Основной шлюз" />
handlePrimaryChange(idx, e.target.checked)} title="Основной шлюз" />
{gw.primary ? 'Основной шлюз' : 'Резервный шлюз'}
{currentGateways.length > 1 && ( )}
))}
Для jumphost/exit должен быть один основной gateway.
)}
); } export default EditServerModal;