diff --git a/backend/server.js b/backend/server.js index 7630cb0..03acfc4 100644 --- a/backend/server.js +++ b/backend/server.js @@ -785,6 +785,74 @@ app.post('/api/server-filters/:serverId', async (req, res) => { } }); +// --- Simple Filters Routes --- + +// Get simple filters +app.get('/api/simple-filters', async (req, res) => { + const params = { + Bucket: BUCKET_NAME, + Key: 'simple-filters.json', + }; + + try { + const data = await s3.getObject(params).promise(); + const fileContent = data.Body.toString('utf-8'); + let filters = []; + + try { + filters = JSON.parse(fileContent); + if (!Array.isArray(filters)) { + filters = []; + } + } catch (parseError) { + console.error('Error parsing simple filters:', parseError); + filters = []; + } + + res.json(filters); + } catch (error) { + if (error.code === 'NoSuchKey') { + res.json([]); // Return empty array if file does not exist + } else { + console.error(error); + res.status(500).send('Error reading simple filters from S3'); + } + } +}); + +// Update simple filters +app.post('/api/simple-filters', async (req, res) => { + const { filters } = req.body; + + // Validate filters structure + if (!Array.isArray(filters)) { + return res.status(400).send('Filters must be an array'); + } + + // Validate each filter has required fields + for (let i = 0; i < filters.length; i++) { + const filter = filters[i]; + if (!filter.community || !filter.gateway) { + return res.status(400).send(`Filter at index ${i} is missing required fields`); + } + } + + const params = { + Bucket: BUCKET_NAME, + Key: 'simple-filters.json', + Body: JSON.stringify(filters, null, 2), // Pretty print JSON + ContentType: 'application/json', + }; + + try { + await s3.putObject(params).promise(); + res.send('Simple filters updated successfully'); + } catch (error) { + console.error(error); + res.status(500).send('Error writing simple filters to S3'); + } +}); + // The "catchall" handler: for any request that doesn't // match one above, send back React's index.html file. app.get('*', (req, res) => { diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx index 510242d..5c10560 100644 --- a/frontend/src/FilterManager.jsx +++ b/frontend/src/FilterManager.jsx @@ -65,6 +65,7 @@ function FilterManager() { useEffect(() => { fetchServers(); + fetchSimpleFilters(); }, []); // Загружаем фильтры при выборе сервера @@ -102,6 +103,19 @@ function FilterManager() { } }; + const fetchSimpleFilters = async () => { + setSimpleLoading(true); + try { + const response = await axios.get(`${API_URL}/simple-filters`); + setSimpleFilters(response.data); + } catch (error) { + console.error('Error fetching simple filters:', error); + setSimpleFilters([]); + } finally { + setSimpleLoading(false); + } + }; + const handleAddServer = async () => { if (!newServer.name.trim()) { setError('Имя сервера обязательно для заполнения.'); @@ -581,22 +595,54 @@ function FilterManager() { }; // Функции для работы с фильтрами в упрощённом режиме - const handleSimpleAddFilter = () => { + const handleSimpleAddFilter = async () => { if (!simpleAddFilter.community.trim() || !simpleAddFilter.gateway.trim()) { setSimpleError('Поля Community и Gateway должны быть заполнены.'); return; } - setSimpleFilters([...simpleFilters, { ...simpleAddFilter }]); + const updatedFilters = [...simpleFilters, { ...simpleAddFilter }]; + setSimpleFilters(updatedFilters); setSimpleAddFilter({ community: '', gateway: '', description: '' }); setSimpleError(''); + + // Сохраняем фильтры + try { + await axios.post(`${API_URL}/simple-filters`, { filters: updatedFilters }); + setSimpleSuccess('Фильтр успешно добавлен!'); + setTimeout(() => setSimpleSuccess(''), 3000); + } catch (error) { + console.error('Error saving simple filters:', error); + setSimpleError('Не удалось сохранить фильтр.'); + } }; - const handleSimpleDeleteFilter = (filter) => { - setSimpleFilters(simpleFilters.filter(f => f !== filter)); + + const handleSimpleDeleteFilter = async (filter) => { + const updatedFilters = simpleFilters.filter(f => f !== filter); + setSimpleFilters(updatedFilters); + + // Сохраняем фильтры + try { + await axios.post(`${API_URL}/simple-filters`, { filters: updatedFilters }); + setSimpleSuccess('Фильтр успешно удален!'); + setTimeout(() => setSimpleSuccess(''), 3000); + } catch (error) { + console.error('Error saving simple filters:', error); + setSimpleError('Не удалось удалить фильтр.'); + } }; - const handleSimpleEditFilter = (index, field, value) => { + + const handleSimpleEditFilter = async (index, field, value) => { const updated = [...simpleFilters]; updated[index][field] = value; setSimpleFilters(updated); + + // Сохраняем фильтры + try { + await axios.post(`${API_URL}/simple-filters`, { filters: updated }); + } catch (error) { + console.error('Error saving simple filters:', error); + setSimpleError('Не удалось сохранить изменения.'); + } }; return ( @@ -1181,9 +1227,21 @@ function FilterManager() { {mode === 'simple' ? (
-

- Фильтры (упрощённый режим) -

+
+
+

+ Фильтры (упрощённый режим) +

+
+ Управление фильтрами community/gateway для всех серверов +
+
+
+
+ {simpleFilters.length} фильтров +
+
+
{simpleError && ( @@ -1203,7 +1261,16 @@ function FilterManager() { - {simpleFilters.length === 0 ? ( + {simpleLoading ? ( + + +
+ Загрузка... +
+ Загрузка фильтров... + + + ) : simpleFilters.length === 0 ? ( Нет фильтров ) : ( simpleFilters.map((filter, idx) => ( @@ -1275,13 +1342,50 @@ function FilterManager() {
- +
+ + + {simpleFilters.length > 0 && ( + + )} +
) : (