refactor(OspfToolsPage): rename and restructure optimal cost hints to probability map for improved clarity and functionality
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m59s

This commit is contained in:
2026-03-05 17:05:34 +07:00
parent 81347c6c8d
commit fd9b8b3c22
+40 -15
View File
@@ -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() {
<div className="list-group list-group-flush">
{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 (
<div