diff --git a/frontend/src/FirewallPage.jsx b/frontend/src/FirewallPage.jsx index 532ea52..6ba84ef 100644 --- a/frontend/src/FirewallPage.jsx +++ b/frontend/src/FirewallPage.jsx @@ -231,6 +231,8 @@ export default function FirewallPage() { const [applying, setApplying] = useState(false); const [ipInfoMap, setIpInfoMap] = useState({}); const [ipInfoLoading, setIpInfoLoading] = useState(false); + const [applyConfirmRow, setApplyConfirmRow] = useState(null); + const [applyingRow, setApplyingRow] = useState(null); const routerServers = useMemo( () => @@ -327,26 +329,46 @@ export default function FirewallPage() { return () => { cancelled = true; }; }, [analysisResult?.suggestions]); + const applyPayload = applyConfirmRow + ? { removeIds: applyConfirmRow.ids, addEntries: [applyConfirmRow.addEntry] } + : analysisResult?.suggestions?.length + ? { + removeIds: analysisResult.suggestions.flatMap((s) => s.ids), + addEntries: analysisResult.suggestions.map((s) => s.addEntry), + } + : null; + const handleApplySummary = async () => { - if (!serverId || !analysisResult?.suggestions?.length) return; - setApplying(true); + if (!serverId || !applyPayload) return; + const isRow = !!applyConfirmRow; + if (isRow) setApplyingRow(applyConfirmRow.subnet); + else setApplying(true); try { - const removeIds = analysisResult.suggestions.flatMap((s) => s.ids); - const addEntries = analysisResult.suggestions.map((s) => s.addEntry); await api.post('/mikrotik/address-lists/apply-summary', { serverId, - removeIds, - addEntries, + removeIds: applyPayload.removeIds, + addEntries: applyPayload.addEntries, }); - window.notify?.success?.(`Удалено ${removeIds.length} записей, добавлено ${addEntries.length} подсетей.`); + const removed = applyPayload.removeIds.length; + const added = applyPayload.addEntries.length; + window.notify?.success?.(`Удалено ${removed} записей, добавлено ${added} подсетей.`); setApplyConfirmOpen(false); - setAnalysisOpen(false); - setAnalysisResult(null); + setApplyConfirmRow(null); + if (isRow && analysisResult?.suggestions) { + setAnalysisResult((prev) => ({ + ...prev, + suggestions: prev.suggestions.filter((s) => s.subnet !== applyConfirmRow.subnet), + })); + } else { + setAnalysisOpen(false); + setAnalysisResult(null); + } await fetchAddressLists(); } catch (e) { window.notify?.error?.(e?.response?.data?.message || e?.message || 'Ошибка применения'); } finally { setApplying(false); + setApplyingRow(null); } }; @@ -457,10 +479,11 @@ export default function FirewallPage() { setAnalysisOpen(false); setAnalysisResult(null); setApplyConfirmOpen(false); + setApplyConfirmRow(null); setIpInfoMap({}); }} title="Анализ списка ban" - size="lg" + size="xl" >
@@ -504,12 +527,14 @@ export default function FirewallPage() { AS / Хостер Ссылка Действие + Применить {analysisResult.suggestions.map((s) => { const firstIp = s.subnet.split('/')[0]; const info = ipInfoMap[s.subnet]; + const rowApplying = applyingRow === s.subnet; return ( {s.subnet} @@ -532,6 +557,22 @@ export default function FirewallPage() { Удалить {s.count} записей → добавить 1 + + + ); })} @@ -542,9 +583,12 @@ export default function FirewallPage() {
@@ -555,19 +599,24 @@ export default function FirewallPage() { acc + s.ids.length, 0)} записей и добавлено ${analysisResult.suggestions.length} записей (подсети /24). Продолжить?` - : '' + applyConfirmRow + ? `Удалить ${applyConfirmRow.count} записей и добавить 1 запись (подсеть ${applyConfirmRow.subnet}). Продолжить?` + : applyPayload + ? `Будет удалено ${applyPayload.removeIds.length} записей и добавлено ${applyPayload.addEntries.length} записей (подсети /24). Продолжить?` + : '' } confirmText="Применить" cancelText="Отмена" destructive size="md" - loading={applying} + loading={applying || !!applyingRow} onConfirm={handleApplySummary} - onCancel={() => setApplyConfirmOpen(false)} + onCancel={() => { + setApplyConfirmOpen(false); + setApplyConfirmRow(null); + }} /> );