diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx index 147caec..5d03a43 100644 --- a/frontend/src/FilterManager.jsx +++ b/frontend/src/FilterManager.jsx @@ -140,9 +140,7 @@ function FilterManager() { const [serverListModalOpen, setServerListModalOpen] = useState(false); const [serverSearch, setServerSearch] = useState(''); - // Состояние для инлайн-редактирования и массовых действий - const [editingKey, setEditingKey] = useState(null); - const [editingDraft, setEditingDraft] = useState({ community: '', gateway: '', description: '' }); + // Состояние для массовых действий const [selectedFilterKeys, setSelectedFilterKeys] = useState(new Set()); const [confirmState, setConfirmState] = useState({ open: false, text: '', onConfirm: null }); @@ -151,6 +149,39 @@ function FilterManager() { // Inventory servers (from /servers endpoint) const [inventoryServers, setInventoryServers] = useState([]); + // Собираем все gateways из всех серверов для выбора + const allGateways = (() => { + const gws = []; + inventoryServers.forEach(srv => { + if (Array.isArray(srv.gateways)) { + srv.gateways.forEach(gw => { + if (gw.name && !gws.some(g => g.name === gw.name)) { + gws.push({ + name: gw.name, + ip: gw.ip || '', + comment: gw.comment || '', + serverDns: srv.dns || srv.hostName || '', + country: srv.country || '', + primary: gw.primary + }); + } + }); + } + // Также добавляем старое поле gateway если есть + if (srv.gateway && !gws.some(g => g.name === srv.gateway)) { + gws.push({ + name: srv.gateway, + ip: '', + comment: 'Legacy gateway', + serverDns: srv.dns || srv.hostName || '', + country: srv.country || '', + primary: true + }); + } + }); + return gws.sort((a, b) => a.name.localeCompare(b.name)); + })(); + useEffect(() => { (async () => { try { @@ -713,44 +744,6 @@ function FilterManager() { // Убрано сохранение режима в localStorage по просьбе пользователя - const startInlineEdit = (filter) => { - if (!filter) return; - setEditingKey(filterKey(filter)); - setEditingDraft({ - community: filter.community || '', - gateway: filter.gateway || '', - description: filter.description || '' - }); - }; - - const cancelInlineEdit = () => { - setEditingKey(null); - setEditingDraft({ community: '', gateway: '', description: '' }); - }; - - const saveInlineEdit = async () => { - if (!editingDraft.community.trim() || !editingDraft.gateway.trim()) { - setError('Поля Community и Gateway должны быть заполнены.'); - return; - } - const updated = serverFilters.map((f) => - filterKey(f) === editingKey - ? { community: editingDraft.community.trim(), gateway: editingDraft.gateway.trim(), description: editingDraft.description } - : f - ); - setServerFilters(updated); - cancelInlineEdit(); - setSelectedFilterKeys(new Set()); - try { - await api.post(`/server-filters/${selectedServer.id}`, { filters: updated }); - setSuccess('Фильтр успешно обновлен!'); - setTimeout(() => setSuccess(''), 3000); - } catch (error) { - console.error('Error saving server filters:', error); - setError('Не удалось сохранить фильтр.'); - } - }; - const toggleSelectFilter = (key) => { setSelectedFilterKeys((prev) => { const next = new Set(prev); @@ -1250,10 +1243,9 @@ function FilterManager() { {processedFilters.filter(f => f != null).map((filter, index) => { const key = filterKey(filter); - const isEditing = editingKey === key; const isSelected = selectedFilterKeys.has(key); return ( - + - {isEditing ? ( - setEditingDraft({ ...editingDraft, community: e.target.value })} - autoFocus - /> - ) : ( -
- - - - {filter?.community || ''} -
- )} +
+ + + + {filter?.community || ''} +
- {isEditing ? ( - setEditingDraft({ ...editingDraft, gateway: e.target.value })} - /> - ) : ( -
- - - - {filter?.gateway || ''} -
- )} +
+ + + + {filter?.gateway || ''} +
- {isEditing ? ( - setEditingDraft({ ...editingDraft, description: e.target.value })} - /> - ) : ( -
- {filter?.description ? ( - {filter.description} - ) : ( - Без описания - )} -
- )} +
+ {filter?.description ? ( + {filter.description} + ) : ( + Без описания + )} +
- {isEditing ? ( - <> - - - - ) : ( - <> - - - - )} + +
@@ -1403,16 +1357,50 @@ function FilterManager() { helpText="Введите community в формате AS:VALUE" /> - setNewFilter({ ...newFilter, gateway: val })} - placeholder="192.168.1.1 или gateway-name" - required - icon={IconServer} - helpText="IP адрес или имя шлюза" - /> +
+ + + {allGateways.length === 0 && ( +
+ + Нет доступных gateway. Добавьте шлюзы в разделе Серверы. +
+ )} + {newFilter.gateway && ( +
+ {(() => { + const selected = allGateways.find(g => g.name === newFilter.gateway); + if (!selected) return null; + return ( +
+ + {selected.country ? countryToFlag(selected.country) : } + +
+
{selected.name}
+
+ {[selected.ip, selected.serverDns, selected.comment].filter(Boolean).join(' · ')} +
+
+ {selected.primary && Основной} +
+ ); + })()} +
+ )} +
handleSaveEditFilter(editingFilter)} title="Редактировать фильтр" submitLabel="Сохранить изменения" submitIcon={IconCheck} @@ -1448,15 +1436,61 @@ function FilterManager() { icon={IconHash} /> - setEditingFilter({ ...editingFilter, gateway: val })} - placeholder="192.168.1.1 или gateway-name" - required - icon={IconServer} - /> +
+ + + {allGateways.length === 0 && ( +
+ + Нет доступных gateway. Добавьте шлюзы в разделе Серверы. +
+ )} + {editingFilter.gateway && ( +
+ {(() => { + const selected = allGateways.find(g => g.name === editingFilter.gateway); + if (!selected) { + return ( +
+ +
Gateway "{editingFilter.gateway}" не найден в списке серверов
+
+ ); + } + return ( +
+ + {selected.country ? countryToFlag(selected.country) : } + +
+
{selected.name}
+
+ {[selected.ip, selected.serverDns, selected.comment].filter(Boolean).join(' · ')} +
+
+ {selected.primary && Основной} +
+ ); + })()} +
+ )} +