From fd9b8b3c221c632378e0b30fe097bf66d97e75fc Mon Sep 17 00:00:00 2001 From: shats Date: Thu, 5 Mar 2026 17:05:34 +0700 Subject: [PATCH] refactor(OspfToolsPage): rename and restructure optimal cost hints to probability map for improved clarity and functionality --- frontend/src/OspfToolsPage.jsx | 55 ++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/frontend/src/OspfToolsPage.jsx b/frontend/src/OspfToolsPage.jsx index 458dc3c..32a61b1 100644 --- a/frontend/src/OspfToolsPage.jsx +++ b/frontend/src/OspfToolsPage.jsx @@ -76,7 +76,7 @@ function buildOspfTemplatesFromRouterResults(routerResults = [], servers = []) { return Array.from(byComposite.values()); } -function buildOptimalCostHints(routeOptimizerData, servers = []) { +function buildOptimizerProbabilityMap(routeOptimizerData, servers = []) { const homes = Array.isArray(routeOptimizerData?.homes) ? routeOptimizerData.homes : []; const byRef = new Map(); (servers || []).forEach((server) => { @@ -85,7 +85,7 @@ function buildOptimalCostHints(routeOptimizerData, servers = []) { .forEach((ref) => byRef.set(String(ref), server)); }); - const hints = {}; + const probabilities = {}; homes.forEach((entry) => { const homeRefCandidates = [ @@ -119,18 +119,15 @@ function buildOptimalCostHints(routeOptimizerData, servers = []) { uniqueIface.forEach((candidate, idx) => { const iface = String(candidate?.interfaceName || '').trim(); const hintKey = `${identity.key}::${iface.toUpperCase()}`; - const nextHint = { - optimalCost: (idx + 1) * OSPF_COST_STEP, - probabilityOptimal: Number(candidate?.probabilityOptimal || 0), - }; - const prev = hints[hintKey]; - if (!prev || nextHint.probabilityOptimal > prev.probabilityOptimal) { - hints[hintKey] = nextHint; + const probabilityOptimal = Number(candidate?.probabilityOptimal || 0); + const prev = probabilities[hintKey]; + if (prev == null || probabilityOptimal > prev) { + probabilities[hintKey] = probabilityOptimal; } }); }); - return hints; + return probabilities; } export default function OspfToolsPage() { @@ -141,7 +138,7 @@ export default function OspfToolsPage() { const [optimizerLoading, setOptimizerLoading] = useState(false); const [saving, setSaving] = useState(false); const [dragging, setDragging] = useState(null); - const [optimalHints, setOptimalHints] = useState({}); + const [optimizerProbabilities, setOptimizerProbabilities] = useState({}); const groupedByRouter = useMemo(() => { const grouped = {}; @@ -171,6 +168,34 @@ export default function OspfToolsPage() { .sort((a, b) => a.area.localeCompare(b.area)), })); }, [templates, servers]); + const optimalHints = useMemo(() => { + const hints = {}; + + groupedByRouter.forEach((routerGroup) => { + (routerGroup.areas || []).forEach((areaGroup) => { + const ranked = [...(areaGroup.items || [])] + .map((item) => { + const ifaceKey = `${routerGroup.routerKey}::${String(item.interfaceName || '').toUpperCase()}`; + const probabilityOptimal = Number(optimizerProbabilities[ifaceKey] || 0); + return { item, probabilityOptimal }; + }) + .sort((a, b) => + Number(b.probabilityOptimal || 0) - Number(a.probabilityOptimal || 0) || + String(a.item.interfaceName || '').localeCompare(String(b.item.interfaceName || '')) + ); + + ranked.forEach(({ item, probabilityOptimal }, idx) => { + const hintKey = `${routerGroup.routerKey}::${areaGroup.area}::${String(item.interfaceName || '').toUpperCase()}`; + hints[hintKey] = { + optimalCost: (idx + 1) * OSPF_COST_STEP, + probabilityOptimal, + }; + }); + }); + }); + + return hints; + }, [groupedByRouter, optimizerProbabilities]); const routerColumnClass = groupedByRouter.length > 1 ? 'col-12 col-xxl-6' : 'col-12'; const loadServers = async () => { @@ -208,11 +233,11 @@ export default function OspfToolsPage() { setOptimizerLoading(true); try { const response = await api.get('/route-optimizer', { timeout: 30000 }); - const hints = buildOptimalCostHints(response?.data, servers); - setOptimalHints(hints); + const probabilities = buildOptimizerProbabilityMap(response?.data, servers); + setOptimizerProbabilities(probabilities); } catch (error) { console.error('Failed to load route optimizer hints:', error); - setOptimalHints({}); + setOptimizerProbabilities({}); if (!silent) notify.warning('Не удалось загрузить рекомендации из оптимизатора маршрутов'); } finally { setOptimizerLoading(false); @@ -346,7 +371,7 @@ export default function OspfToolsPage() {
{areaGroup.items.map((item) => ( (() => { - const hint = optimalHints[`${routerGroup.routerKey}::${String(item.interfaceName || '').toUpperCase()}`]; + const hint = optimalHints[`${routerGroup.routerKey}::${areaGroup.area}::${String(item.interfaceName || '').toUpperCase()}`]; const hintMatches = hint && Number(hint.optimalCost) === Number(item.cost); return (