From 07ff184ef402b80efdfd8f27cb33f10e82241382 Mon Sep 17 00:00:00 2001 From: Denis Shatskiy Date: Mon, 14 Jul 2025 08:27:18 +0700 Subject: [PATCH] refactor: Update filter configuration generation and improve UI layout in FilterManager for better readability and consistency --- backend/server.js | 79 ++++++++++++++++++++++++++++------ frontend/src/FilterManager.jsx | 37 ++++++++-------- 2 files changed, 84 insertions(+), 32 deletions(-) diff --git a/backend/server.js b/backend/server.js index bd40bb6..c589344 100644 --- a/backend/server.js +++ b/backend/server.js @@ -308,7 +308,7 @@ app.get('/api/filters/generate-config', async (req, res) => { } if (filters.length === 0) { - return res.json({ config: '// Нет фильтров для генерации конфигурации' }); + return res.json({ config: '// No filters to generate configuration' }); } // Group filters by gateway @@ -320,10 +320,13 @@ app.get('/api/filters/generate-config', async (req, res) => { gatewayGroups[filter.gateway].push(filter.community); }); - let config = '// Конфигурация фильтра frouting для MikroTik 7.14+\n'; - config += '// Сгенерировано автоматически\n\n'; + let config = '// Frouting filter configuration for MikroTik 7.14+\n'; + config += '// Generated automatically\n'; + config += `// Date: ${new Date().toISOString()}\n\n`; - Object.entries(gatewayGroups).forEach(([gateway, communities]) => { + // Если есть только один gateway, создаем простую конфигурацию + if (Object.keys(gatewayGroups).length === 1) { + const [gateway, communities] = Object.entries(gatewayGroups)[0]; config += `if (\n`; communities.forEach((community, index) => { config += `(bgp-communities includes ${community})`; @@ -331,13 +334,37 @@ app.get('/api/filters/generate-config', async (req, res) => { config += ` \nor `; } }); - config += `\n)\n{\n set gw ${gateway}; accept;\n}\nelse\n{\n reject;\n}\n\n`; - }); + config += `\n)\n{\n set gw ${gateway}; accept;\n}\nelse\n{\n reject;\n}\n`; + } else { + // Если несколько gateway, создаем каскадную структуру + const gatewayEntries = Object.entries(gatewayGroups); + gatewayEntries.forEach(([gateway, communities], gatewayIndex) => { + if (gatewayIndex === 0) { + config += `if (\n`; + } else { + config += `else if (\n`; + } + + communities.forEach((community, index) => { + config += `(bgp-communities includes ${community})`; + if (index < communities.length - 1) { + config += ` \nor `; + } + }); + config += `\n)\n{\n set gw ${gateway}; accept;\n}`; + + if (gatewayIndex === gatewayEntries.length - 1) { + config += `\nelse\n{\n reject;\n}\n`; + } else { + config += `\n`; + } + }); + } res.json({ config }); } catch (error) { if (error.code === 'NoSuchKey') { - res.json({ config: '// Файл filters.json не найден' }); + res.json({ config: '// filters.json file not found' }); } else { console.error(error); res.status(500).send('Error generating configuration'); @@ -380,11 +407,13 @@ app.post('/api/filters/export-config', async (req, res) => { gatewayGroups[filter.gateway].push(filter.community); }); - let config = '// Конфигурация фильтра frouting для MikroTik 7.14+\n'; - config += '// Сгенерировано автоматически\n'; - config += `// Дата: ${new Date().toISOString()}\n\n`; + let config = '// Frouting filter configuration for MikroTik 7.14+\n'; + config += '// Generated automatically\n'; + config += `// Date: ${new Date().toISOString()}\n\n`; - Object.entries(gatewayGroups).forEach(([gateway, communities]) => { + // Если есть только один gateway, создаем простую конфигурацию + if (Object.keys(gatewayGroups).length === 1) { + const [gateway, communities] = Object.entries(gatewayGroups)[0]; config += `if (\n`; communities.forEach((community, index) => { config += `(bgp-communities includes ${community})`; @@ -392,8 +421,32 @@ app.post('/api/filters/export-config', async (req, res) => { config += ` \nor `; } }); - config += `\n)\n{\n set gw ${gateway}; accept;\n}\nelse\n{\n reject;\n}\n\n`; - }); + config += `\n)\n{\n set gw ${gateway}; accept;\n}\nelse\n{\n reject;\n}\n`; + } else { + // Если несколько gateway, создаем каскадную структуру + const gatewayEntries = Object.entries(gatewayGroups); + gatewayEntries.forEach(([gateway, communities], gatewayIndex) => { + if (gatewayIndex === 0) { + config += `if (\n`; + } else { + config += `else if (\n`; + } + + communities.forEach((community, index) => { + config += `(bgp-communities includes ${community})`; + if (index < communities.length - 1) { + config += ` \nor `; + } + }); + config += `\n)\n{\n set gw ${gateway}; accept;\n}`; + + if (gatewayIndex === gatewayEntries.length - 1) { + config += `\nelse\n{\n reject;\n}\n`; + } else { + config += `\n`; + } + }); + } // Save configuration to S3 const exportParams = { diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx index d8542e9..460b322 100644 --- a/frontend/src/FilterManager.jsx +++ b/frontend/src/FilterManager.jsx @@ -405,35 +405,31 @@ function FilterManager() {

Фильтры frouting ({filteredFilters.length})

- +
- - - - + + {filteredFilters.map((filter, index) => ( - - + - - -
handleSort('community')} - > + handleSort('community')}> Community {sortField === 'community' && ( )} handleSort('gateway')} - > + handleSort('gateway')}> Gateway {sortField === 'gateway' && ( )} ОписаниеДействияОписание
+
{editingFilter === filter.community ? ( handleEditKeyDown(e, filter.community)} + style={{minWidth: '120px'}} /> ) : ( - {filter.community} + {filter.community} )} + {editingFilter === filter.community ? ( handleEditKeyDown(e, filter.community)} + style={{minWidth: '120px'}} /> ) : ( - {filter.gateway} + {filter.gateway} )} + {editingFilter === filter.community ? ( handleEditKeyDown(e, filter.community)} + style={{minWidth: '120px'}} /> ) : ( {filter.description} )} -
+
+
{editingFilter === filter.community ? ( <>