diff --git a/frontend/src/ServerManager.jsx b/frontend/src/ServerManager.jsx index f735a9f..3ccb232 100644 --- a/frontend/src/ServerManager.jsx +++ b/frontend/src/ServerManager.jsx @@ -1446,24 +1446,30 @@ function ServerManager() { function EditServerModal({ show, server, onChange, onSave, onClose }) { const modalRef = useRef(null); // Локальное состояние для формы - const [localServer, setLocalServer] = useState(server || {}); + const [localServer, setLocalServer] = useState({}); + // Функция для создания сервера с гарантированными gateways const ensureGateways = (srv) => { - if (!srv) return {}; + if (!srv) return { gateways: [] }; const needs = NEEDS_GATEWAYS(srv.type); - let gateways = needs ? normalizeGateways(srv.gateways, srv.gateway || srv.dns || srv.ip) : []; - if (needs && gateways.length === 0) { - gateways = [makeGateway({ primary: true })]; + 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(() => { - setLocalServer(ensureGateways(server || {})); - }, [server]); - - const gateways = Array.isArray(localServer?.gateways) ? localServer.gateways : []; + if (show && server) { + const prepared = ensureGateways(server); + console.log('[EditServerModal] Инициализация с сервером:', prepared); + setLocalServer(prepared); + } + }, [show, server]); useEffect(() => { if (window.Tabler && window.Tabler.Modal && modalRef.current) { @@ -1484,12 +1490,80 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) { } }, [show, onClose]); - const handleChange = (field, value) => { - const updated = { ...localServer, [field]: value }; - setLocalServer(updated); - onChange && onChange(updated); + // Универсальная функция обновления поля + 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; + }); + }; + + // Функция переключения primary шлюза + 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 + })); + // Убедимся, что хотя бы один primary + 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 = () => { + console.log('[EditServerModal] handleAddGateway вызвана, текущий localServer:', localServer); + 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 }; + console.log('[EditServerModal] Новый localServer после добавления шлюза:', updated); + 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); + // Убедимся, что есть primary + 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 (
@@ -1502,35 +1576,35 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {
{ e.preventDefault(); onSave && onSave(localServer); }}>
- handleChange('id', e.target.value)} placeholder="srv-1" /> + handleFieldChange('id', e.target.value)} placeholder="srv-1" />
- handleChange('ip', e.target.value)} /> + handleFieldChange('ip', e.target.value)} />
- handleChange('extIp', e.target.value)} placeholder="публичный IP, если отличается" /> + handleFieldChange('extIp', e.target.value)} placeholder="публичный IP, если отличается" />
- handleChange('internalIp', e.target.value)} placeholder="10.x.x.x / 192.168.x.x" /> + handleFieldChange('internalIp', e.target.value)} placeholder="10.x.x.x / 192.168.x.x" />
- handleChange('dns', e.target.value)} /> + handleFieldChange('dns', e.target.value)} />
- handleChange('country', e.target.value)} /> + handleFieldChange('country', e.target.value)} />
- handleChange('provider', e.target.value)} /> + handleFieldChange('provider', e.target.value)} />
- handleFieldChange('type', e.target.value)}> {SERVER_TYPE_OPTIONS.map((opt) => ( ))} @@ -1538,14 +1612,14 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {
- handleChange('tunnel', e.target.value)} /> + handleFieldChange('tunnel', e.target.value)} />
- {NEEDS_GATEWAYS(localServer.type) && ( + {showGateways && ( <> -
Шлюзы
+
Шлюзы ({currentGateways.length})
- {(localServer.gateways || []).map((gw, idx) => ( -
+ {currentGateways.map((gw, idx) => ( +
@@ -1553,12 +1627,7 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) { type="text" className="form-control" value={gw.name || ''} - onChange={(e) => { - const list = (localServer.gateways || []).map((g, i) => i === idx ? { ...g, name: e.target.value } : g); - const next = { ...localServer, gateways: list }; - setLocalServer(next); - onChange && onChange(next); - }} + onChange={(e) => handleGatewayChange(idx, 'name', e.target.value)} placeholder="GW-MSK" required /> @@ -1569,12 +1638,7 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) { type="text" className="form-control" value={gw.ip || ''} - onChange={(e) => { - const list = (localServer.gateways || []).map((g, i) => i === idx ? { ...g, ip: e.target.value } : g); - const next = { ...localServer, gateways: list }; - setLocalServer(next); - onChange && onChange(next); - }} + onChange={(e) => handleGatewayChange(idx, 'ip', e.target.value)} placeholder="10.0.0.1" />
@@ -1584,12 +1648,7 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) { type="text" className="form-control" value={gw.comment || ''} - onChange={(e) => { - const list = (localServer.gateways || []).map((g, i) => i === idx ? { ...g, comment: e.target.value } : g); - const next = { ...localServer, gateways: list }; - setLocalServer(next); - onChange && onChange(next); - }} + onChange={(e) => handleGatewayChange(idx, 'comment', e.target.value)} placeholder="Основной шлюз" />
@@ -1598,14 +1657,8 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) { { - const list = (localServer.gateways || []).map((g, i) => ({ ...g, primary: i === idx ? e.target.checked : false })); - if (!list.some(g => g.primary)) list[idx].primary = true; - const next = { ...localServer, gateways: list }; - setLocalServer(next); - onChange && onChange(next); - }} + checked={!!gw.primary} + onChange={(e) => handlePrimaryChange(idx, e.target.checked)} title="Основной шлюз" />
@@ -1613,17 +1666,11 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {
{gw.primary ? 'Основной шлюз' : 'Резервный шлюз'}
- {(localServer.gateways || []).length > 1 && ( + {currentGateways.length > 1 && ( @@ -1635,19 +1682,7 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {