diff --git a/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/LinkDetail.tsx b/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/LinkDetail.tsx index 07104a69..4ae5478c 100644 --- a/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/LinkDetail.tsx +++ b/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/LinkDetail.tsx @@ -175,8 +175,8 @@ const SelectedLink = ({ ); }; -const LinkFeatureDetail = ({ actual, reference }: LinkMapFeature) => { - const linkToShow = reference ?? actual; +const LinkFeatureDetail = ({ linkToShow, actual }: LinkMapFeature) => { + // const linkToShow = reference ?? actual; const [selectedLink, setSelectedLink] = useState(0); const { errors } = usePointToPointErrors({ id: linkToShow.id, @@ -224,12 +224,15 @@ const LinkFeatureDetail = ({ actual, reference }: LinkMapFeature) => { ); }; -export const LinkReferenceStatus = ({ reference }: LinkMapFeature) => { +export const LinkReferenceStatus = ({ + linkToShow, + reference, +}: LinkMapFeature) => { const isNewLink = !reference; const { errors } = usePointToPointErrors({ - id: reference.id, - type: reference.type, + id: linkToShow.id, + type: linkToShow.type, }); const { @@ -240,7 +243,7 @@ export const LinkReferenceStatus = ({ reference }: LinkMapFeature) => { // Check if there are errors of global reference state to shown const { reference: fetchDataReference } = getQueryByLinkType( - reference.type + linkToShow.type ); const { data: referenceData, isError: isReferenceError } = fetchDataReference({}); @@ -263,68 +266,56 @@ export const LinkReferenceStatus = ({ reference }: LinkMapFeature) => { }; if (!allNodes) return {}; // Then reduce the nodes to update - return reference.nodes.reduce((acc, node) => { + return linkToShow.nodes.reduce((acc, node) => { // If the node with node name exist get the ipv4 and hostname if (allNodes[node]) { acc[allNodes[node].ipv4] = allNodes[node].hostname; } return acc; }, {}); - }, [meshWideNodesReference, meshWideNodesActual, reference.nodes]); + }, [meshWideNodesReference, meshWideNodesActual, linkToShow.nodes]); // Mutation to update the reference state const { callMutations } = useSetLinkReferenceState({ - linkType: reference.type, - linkToUpdate: reference, + linkType: linkToShow.type, + linkToUpdate: linkToShow, isDown, + isNewLink, nodesToUpdate, }); // Show confirmation modal before run mutations const setReferenceState = useCallback(async () => { - confirmModal( - reference.type, - Object.values(nodesToUpdate), - isDown, - async () => { - try { - const res = await callMutations(); - if (res.errors.length) { - console.log("Errors"); - throw new Error("Error setting new reference state!"); - } - showToast({ - text: New reference state set!, - }); - } catch (error) { - showToast({ - text: Error setting new reference state!, - }); - } finally { - closeModal(); - } + try { + const res = await callMutations(); + if (res.errors.length) { + console.log("Errors"); + throw new Error("Error setting new reference state!"); } - ); - }, [ - callMutations, - closeModal, - confirmModal, - isDown, - nodesToUpdate, - reference.type, - showToast, - ]); + showToast({ + text: New reference state set!, + }); + } catch (error) { + showToast({ + text: Error setting new reference state!, + }); + } finally { + closeModal(); + } + }, [callMutations, closeModal, showToast]); let btnText = ( Set reference state for this -
{dataTypeNameMapping(reference.type)} +
{dataTypeNameMapping(linkToShow.type)}
); - if (isDown) { + // If is down and not a new link. + // Could happen that one of the links is not on the state yet and the other is not + if (isDown && !isNewLink) { btnText = ( - Delete this {dataTypeNameMapping(reference.type)} + Delete this {dataTypeNameMapping(linkToShow.type)}
from reference state
@@ -332,14 +323,15 @@ export const LinkReferenceStatus = ({ reference }: LinkMapFeature) => { } let errorMessage = Same status as in the reference state; - if (referenceError) { - errorMessage = Reference is not set or has errors; - } else if (errors?.hasErrors) { - errorMessage = This link has errors; - } else if (isNewLink) { + + if (isNewLink) { errorMessage = ( This Link is not registered on the reference state ); + } else if (referenceError) { + errorMessage = Reference is not set or has errors; + } else if (errors?.hasErrors) { + errorMessage = This link has errors; } const hasError = errors?.hasErrors || referenceError; @@ -350,7 +342,14 @@ export const LinkReferenceStatus = ({ reference }: LinkMapFeature) => { + confirmModal({ + dataType: linkToShow.type, + nodes: Object.values(nodesToUpdate), + isDown, + cb: setReferenceState, + }) + } > {errorMessage} diff --git a/plugins/lime-plugin-mesh-wide/src/components/Map/LinkLine.tsx b/plugins/lime-plugin-mesh-wide/src/components/Map/LinkLine.tsx index 8833242e..d078c525 100644 --- a/plugins/lime-plugin-mesh-wide/src/components/Map/LinkLine.tsx +++ b/plugins/lime-plugin-mesh-wide/src/components/Map/LinkLine.tsx @@ -38,7 +38,11 @@ export const LinkLine = ({ referenceLink, actualLink }: ILinkLineProps) => { const _setSelectedFeature = () => { setSelectedMapFeature({ id: linkToShow.id, - feature: { reference: linkToShow, actual: actualLink }, + feature: { + reference: referenceLink, + actual: actualLink, + linkToShow, + }, type: "link", }); }; diff --git a/plugins/lime-plugin-mesh-wide/src/components/configPage/modals.tsx b/plugins/lime-plugin-mesh-wide/src/components/configPage/modals.tsx index a0c1beb1..4fde5161 100644 --- a/plugins/lime-plugin-mesh-wide/src/components/configPage/modals.tsx +++ b/plugins/lime-plugin-mesh-wide/src/components/configPage/modals.tsx @@ -120,12 +120,17 @@ export const useSetNodeInfoReferenceStateModal = () => { export const useSetLinkReferenceStateModal = () => { const { toggleModal, setModalState, isModalOpen, closeModal } = useModal(); - const confirmModal = ( - dataType: MeshWideMapDataTypeKeys, - nodes: string[], - isDown: boolean, - cb: () => Promise - ) => { + const confirmModal = ({ + dataType, + nodes, + isDown, + cb, + }: { + dataType: MeshWideMapDataTypeKeys; + nodes: string[]; + isDown: boolean; + cb: () => Promise; + }) => { let title = ( Set reference state for this {dataTypeNameMapping(dataType)}? diff --git a/plugins/lime-plugin-mesh-wide/src/lib/links/getLinksCoordinates.ts b/plugins/lime-plugin-mesh-wide/src/lib/links/getLinksCoordinates.ts index 19ad7d69..5338aa46 100644 --- a/plugins/lime-plugin-mesh-wide/src/lib/links/getLinksCoordinates.ts +++ b/plugins/lime-plugin-mesh-wide/src/lib/links/getLinksCoordinates.ts @@ -2,6 +2,7 @@ import { MacToMacLink, PontToPointLink, } from "plugins/lime-plugin-mesh-wide/src/lib/links/PointToPointLink"; +import { isValidCoordinate } from "plugins/lime-plugin-mesh-wide/src/lib/utils"; import { IBaseLink, ILinks, @@ -18,91 +19,119 @@ export const mergeLinksAndCoordinates = ( nodes?: INodes ): LocatedLinkData => { if (!links || isEmpty(links)) return {}; - const result: LocatedLinkData = {}; - // for every node check all links - for (const actualNodeName in links) { - if ( - isEmpty(links[actualNodeName]) || - typeof links[actualNodeName].links !== "object" // todo(kon): this is an error from the backend - ) - continue; - const srcLoc = links[actualNodeName].src_loc; - for (const [linkKey, linkData] of Object.entries( - links[actualNodeName].links - )) { - // Find destination link info from shared state - let dest: IBaseLink; - for (const destNodeKey in links) { - // Prevent empty objects crashing from shared state - if (links[destNodeKey] && !isEmpty(links[destNodeKey]?.links)) { - const link = Object.entries(links[destNodeKey].links).find( - ([key]) => - key === linkKey && destNodeKey !== actualNodeName - ); - if (link) { - dest = { [destNodeKey]: link[1] }; + + try { + // for every node check all links + for (const actualNodeName in links) { + if ( + isEmpty(links[actualNodeName]) || + typeof links[actualNodeName].links !== "object" // todo(kon): this is an error from the backend + ) { + continue; + } + const srcLoc = links[actualNodeName].src_loc; + // If the source location is not valid (FIXME coords), continue + if (!isValidCoordinate(srcLoc.lat, srcLoc.long)) { + continue; + } + + for (const [linkKey, linkData] of Object.entries( + links[actualNodeName].links + )) { + // Find destination link info from shared state + let dest: IBaseLink = {}; + for (const destNodeKey in links) { + // Prevent empty objects crashing from shared state + if ( + links[destNodeKey] && + !isEmpty(links[destNodeKey]?.links) + ) { + const link = Object.entries( + links[destNodeKey].links + ).find( + ([key]) => + key === linkKey && + destNodeKey !== actualNodeName + ); + if (link) { + dest = { [destNodeKey]: link[1] }; + } } } - } - let destLoc = linkData?.dst_loc; - // If destination coords are undefined, try to find it on other ways. - if (!destLoc) { - if (dest && links[Object.keys(dest)[0]].src_loc) { - // If we have destination link info, try to find the src_loc - destLoc = links[Object.keys(dest)[0]].src_loc; - } else { - // Find the destination MAC between existing located nodes to get the position - const dstNode = Object.values(nodes).find((node) => { - return node.macs.find((mac) => { - return ( - mac.toLowerCase() === - linkData.dst_mac.toLowerCase() - ); + let destLoc = linkData?.dst_loc; + // If destination coords are undefined, try to find it on other ways. + if (!destLoc) { + if ( + dest && + !isEmpty(dest) && + links[Object.keys(dest)[0]]?.src_loc + ) { + // If we have destination link info, try to find the src_loc + destLoc = links[Object.keys(dest)[0]].src_loc; + } else { + // Find the destination MAC between existing located nodes to get the position + const dstNode = Object.values(nodes).find((node) => { + return node.macs.find((mac) => { + return ( + mac.toLowerCase() === + linkData?.dst_mac?.toLowerCase() + ); + }); }); - }); - if (dstNode) { - destLoc = dstNode.coordinates; + if (dstNode) { + destLoc = dstNode.coordinates; + } } } - } - // What happen if the destination link or location is undefined? - // Maybe drawing somehow to the map and show the user that the link is not complete - // For the moment lets ignore the link - if (!destLoc) { - continue; - } + // What happen if the destination link or location is undefined? + // Maybe drawing somehow to the map and show the user that the link is not complete + // For the moment lets ignore the link + if ( + !destLoc || + (destLoc && !isValidCoordinate(destLoc.lat, destLoc.long)) // FIXME coords + ) { + continue; + } - // Get Geolink key to check if is already added - const geoLinkKey = PontToPointLink.generateId(srcLoc, destLoc); + // Get Geolink key to check if is already added + const geoLinkKey = PontToPointLink.generateId(srcLoc, destLoc); - // If the link PontToPointLink already exists and the link is already added, ignore it - if (result[geoLinkKey] && result[geoLinkKey].linkExists(linkKey)) { - continue; - } + // If the link PontToPointLink already exists and the link is already added, ignore it + if ( + result[geoLinkKey] && + result[geoLinkKey].linkExists(linkKey) + ) { + continue; + } - // Instantiate new point to point link on the results array - if (!result[geoLinkKey]) { - result[geoLinkKey] = new PontToPointLink(srcLoc, destLoc); - } + // Instantiate new point to point link on the results array + if (!result[geoLinkKey]) { + result[geoLinkKey] = new PontToPointLink(srcLoc, destLoc); + } - // Add node names to the link data - result[geoLinkKey].addNodes([ - actualNodeName, - ...Object.keys(dest ?? ""), // If destination node is down, ignore node name - ]); + // Add node names to the link data + result[geoLinkKey].addNodes([ + actualNodeName, + ...Object.keys(dest ?? ""), // If destination node is down, ignore node name + ]); - const entry = { - [actualNodeName]: { - ...linkData, - }, - ...dest, - } as IBaseLink; + const entry = { + [actualNodeName]: { + ...linkData, + }, + ...dest, + } as IBaseLink; - result[geoLinkKey].addLink(new MacToMacLink(linkKey, entry, type)); + result[geoLinkKey].addLink( + new MacToMacLink(linkKey, entry, type) + ); + } } + } catch (e) { + console.error("Error merging links and coordinates", e); } return result; diff --git a/plugins/lime-plugin-mesh-wide/src/meshWideQueries.tsx b/plugins/lime-plugin-mesh-wide/src/meshWideQueries.tsx index 9aab0ae3..f3bd9713 100644 --- a/plugins/lime-plugin-mesh-wide/src/meshWideQueries.tsx +++ b/plugins/lime-plugin-mesh-wide/src/meshWideQueries.tsx @@ -23,6 +23,7 @@ import { import { useMeshWideSyncCall } from "utils/meshWideSyncCall"; import { useSharedData } from "utils/useSharedData"; +import { isEmpty } from "utils/utils"; const refetchInterval = 60000; @@ -149,12 +150,14 @@ interface IUseSetLinkReferenceState { nodesToUpdate: { [ip: string]: string }; // { ip: hostname } params?: any; isDown: boolean; + isNewLink: boolean; } export const useSetLinkReferenceState = ({ linkType, linkToUpdate, isDown, + isNewLink, nodesToUpdate, params, }: IUseSetLinkReferenceState) => { @@ -167,13 +170,14 @@ export const useSetLinkReferenceState = ({ mutationFn: ({ ip }) => { const hostname = nodesToUpdate[ip]; - let newReferenceLinks = (referenceData[hostname] ?? + let newReferenceLinks = (referenceData[hostname].links ?? {}) as IBaseLink; - // This is a hotfix because backend returns an empty string somtimes - if (typeof newReferenceLinks !== "object") newReferenceLinks = {}; + + // This is a hotfix because backend returns an empty array sometimes + if (isEmpty(newReferenceLinks)) newReferenceLinks = {}; for (const mactomac of linkToUpdate.links) { - if (isDown) { + if (isDown && newReferenceLinks[mactomac.id] && !isNewLink) { delete newReferenceLinks[mactomac.id]; continue; } @@ -194,6 +198,12 @@ export const useSetLinkReferenceState = ({ }, } as ILinks ); + console.log("linkToUpdate", linkToUpdate); + console.log("newReferenceLinks", newReferenceLinks); + console.log("referenceData", referenceData); + console.log("data[hostname]", data[hostname]); + console.log("hostname", hostname); + console.log("queryKey", queryKey); return doSharedStateApiCall(queryKey, ip); }, ips: Object.keys(nodesToUpdate), diff --git a/plugins/lime-plugin-mesh-wide/src/meshWideTypes.tsx b/plugins/lime-plugin-mesh-wide/src/meshWideTypes.tsx index 71a3d6f3..ba5b5999 100644 --- a/plugins/lime-plugin-mesh-wide/src/meshWideTypes.tsx +++ b/plugins/lime-plugin-mesh-wide/src/meshWideTypes.tsx @@ -96,7 +96,8 @@ export type INodes = { [key: string]: INodeInfo }; export type LinkMapFeature = { actual: PontToPointLink; - reference: PontToPointLink; + reference?: PontToPointLink; + linkToShow: PontToPointLink; }; export type NodeMapFeature = {