diff --git a/example/s3/network-config.json b/example/s3/network-config.json index 13c56c3..a33c6e5 100644 --- a/example/s3/network-config.json +++ b/example/s3/network-config.json @@ -5,35 +5,55 @@ "name": "SWE-IHOR", "ip": "94.142.140.1", "description": "Cloudflare Sweden - основной выход", - "serverId": "SWE-HIPHOST" + "serverId": "SWE-HIPHOST", + "country": "SWE", + "type": "direct" }, { "id": "gw-bunny-swe", "name": "SWE-BUNNY", "ip": "94.142.140.2", "description": "Bunny CDN Sweden", - "serverId": "SWE-HIPHOST" + "serverId": "SWE-HIPHOST", + "country": "SWE", + "type": "direct" }, { "id": "gw-telegram-nl", "name": "TG-PROXY-1", "ip": "149.154.167.50", "description": "Telegram DC2", - "serverId": "NL-AMSTERDAM" + "serverId": "NL-AMSTERDAM", + "country": "NL", + "type": "direct" }, { "id": "gw-hetzner-de", "name": "DE-HETZNER", "ip": "195.100.30.21", "description": "Hetzner Frankfurt", - "serverId": "DE-FRANKFURT" + "serverId": "DE-FRANKFURT", + "country": "DE", + "type": "direct" }, { "id": "gw-fastly-us", "name": "US-FASTLY", "ip": "151.101.1.1", "description": "Fastly US East", - "serverId": "US-NEWYORK" + "serverId": "US-NEWYORK", + "country": "US", + "type": "direct" + }, + { + "id": "gw-recursive-swe", + "name": "SWE-RECURSIVE", + "ip": "10.0.0.1", + "description": "Рекурсивный gateway через SWE-IHOR", + "serverId": "SWE-HIPHOST", + "country": "SWE", + "type": "recursive", + "parentGatewayId": "gw-cloudflare-swe" } ], "tunnelInterfaces": [ diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx index af43002..40afd81 100644 --- a/frontend/src/NetworkConfigManager.jsx +++ b/frontend/src/NetworkConfigManager.jsx @@ -50,6 +50,12 @@ const INTERFACE_TYPES = [ { value: 'OpenVPN', label: 'OpenVPN', color: 'orange' }, ]; +// Типы gateway +const GATEWAY_TYPES = [ + { value: 'direct', label: 'Прямой', description: 'Прямой доступ в интернет', color: 'green' }, + { value: 'recursive', label: 'Рекурсивный', description: 'Ссылается на другой gateway', color: 'blue' }, +]; + // Пустые объекты const getEmptyGateway = () => ({ id: `gw-${Date.now()}-${Math.random().toString(16).slice(2, 6)}`, @@ -57,6 +63,9 @@ const getEmptyGateway = () => ({ ip: '', description: '', serverId: '', + country: '', + type: 'direct', + parentGatewayId: '', // Для рекурсивных - ID родительского gateway }); const getEmptyInterface = () => ({ @@ -97,6 +106,7 @@ function NetworkConfigManager() { const [providerFilter, setProviderFilter] = useState(''); const [serverFilter, setServerFilter] = useState(''); const [typeFilter, setTypeFilter] = useState(''); + const [gatewayTypeFilter, setGatewayTypeFilter] = useState(''); // Для фильтрации gateway по типу const [viewMode, setViewMode] = useState('cards'); // 'cards' | 'table' // === Modals === @@ -207,6 +217,10 @@ function NetworkConfigManager() { result = result.filter(g => g.serverId === serverFilter); } + if (gatewayTypeFilter) { + result = result.filter(g => g.type === gatewayTypeFilter); + } + if (searchTerm) { const term = searchTerm.toLowerCase(); result = result.filter(g => { @@ -214,6 +228,7 @@ function NetworkConfigManager() { return ( g.name?.toLowerCase().includes(term) || g.ip?.toLowerCase().includes(term) || + g.country?.toLowerCase().includes(term) || server?.country?.toLowerCase().includes(term) || server?.provider?.toLowerCase().includes(term) || g.description?.toLowerCase().includes(term) || @@ -223,7 +238,7 @@ function NetworkConfigManager() { } return result; - }, [config.gateways, providerFilter, serverFilter, searchTerm, servers]); + }, [config.gateways, providerFilter, serverFilter, typeFilter, searchTerm, servers]); const filteredInterfaces = useMemo(() => { let result = [...(config.tunnelInterfaces || [])]; @@ -292,9 +307,10 @@ function NetworkConfigManager() { setProviderFilter(''); setServerFilter(''); setTypeFilter(''); + setGatewayTypeFilter(''); }; - const hasActiveFilters = searchTerm || providerFilter || serverFilter || typeFilter; + const hasActiveFilters = searchTerm || providerFilter || serverFilter || typeFilter || gatewayTypeFilter; // === CRUD для Gateways === const handleAddGateway = () => { @@ -517,22 +533,39 @@ function NetworkConfigManager() { ); }; + // === Получение родительского gateway === + const getParentGateway = (gatewayId) => { + if (!gatewayId) return null; + return config.gateways?.find(g => g.id === gatewayId); + }; + // === Рендер карточки Gateway === const renderGatewayCard = (gateway) => { const server = getServerInfo(gateway.serverId); const provider = server?.provider || ''; - const country = server?.country || ''; + const serverCountry = server?.country || ''; + const gatewayCountry = gateway.country || ''; + const displayCountry = gatewayCountry || serverCountry; + const gatewayType = GATEWAY_TYPES.find(t => t.value === gateway.type) || GATEWAY_TYPES[0]; + const parentGateway = gateway.type === 'recursive' && gateway.parentGatewayId + ? getParentGateway(gateway.parentGatewayId) + : null; return (
{gateway.ip || '—'}
@@ -963,8 +1023,15 @@ function NetworkConfigManager() {
)}