diff --git a/gui/src/components/decoder/decoder-entry.tsx b/gui/src/components/decoder/decoder-entry.tsx index 8461ff95..f31a8a37 100644 --- a/gui/src/components/decoder/decoder-entry.tsx +++ b/gui/src/components/decoder/decoder-entry.tsx @@ -16,7 +16,7 @@ import { TextField, Typography, } from "@mui/material"; -import React from "react"; +import React, { useEffect } from "react"; import MapRoundedIcon from "@mui/icons-material/MapRounded"; import DeleteIcon from "@mui/icons-material/Delete"; import DownloadIcon from "@mui/icons-material/Download"; @@ -53,6 +53,14 @@ export const DecoderEntry = (props: DecoderDataEntry & DecoderEntryProps) => { onDeleted, } = props; + const [localText, setLocalText] = React.useState(text); + const [previouslySubmittedText, setPreviouslySubmittedText] = React.useState(text); + + useEffect(() => { + setLocalText(text); + setPreviouslySubmittedText(""); + }, [id]); + const getIntersectionId = (decodedResponse: DecoderApiResponseGeneric | undefined) => { if (!decodedResponse) { return undefined; @@ -75,8 +83,18 @@ export const DecoderEntry = (props: DecoderDataEntry & DecoderEntryProps) => { onSelected(id); }; - const handleTextChange = (event: React.FocusEvent) => { - onTextChanged(id, event.target.value); + const handleKeyDown = (event) => { + if (event.key === "Enter" && previouslySubmittedText !== localText) { + onTextChanged(id, localText); + setPreviouslySubmittedText(localText); + } + }; + + const handleBlur = () => { + if (previouslySubmittedText !== localText) { + onTextChanged(id, localText); + setPreviouslySubmittedText(localText); + } }; const handleDeleteClick = () => { @@ -175,7 +193,14 @@ export const DecoderEntry = (props: DecoderDataEntry & DecoderEntryProps) => { )}

- + setLocalText(e.target.value)} + onBlur={handleBlur} + onKeyDown={handleKeyDown} + sx={{ width: 160 }} + /> @@ -188,15 +213,22 @@ export const DecoderEntry = (props: DecoderDataEntry & DecoderEntryProps) => { )} {status === "IN_PROGRESS" && } - - - + {decodedResponse?.decodeErrors !== "" && decodedResponse?.decodeErrors !== undefined && ( + + + {"Errors: " + (decodedResponse?.decodeErrors == "" ? "None" : decodedResponse?.decodeErrors) ?? "None"} + + + )} ); diff --git a/gui/src/components/decoder/decoder-tables.tsx b/gui/src/components/decoder/decoder-tables.tsx index 77538b88..fda880a8 100644 --- a/gui/src/components/decoder/decoder-tables.tsx +++ b/gui/src/components/decoder/decoder-tables.tsx @@ -54,9 +54,8 @@ export const DecoderTables = (props: DecoderTableProps) => { case "SPAT": const spatPayload = decodedResponse.processedSpat; return spatPayload?.intersectionId; - case "BSM": - const bsmPayload = decodedResponse.bsm; - return bsmPayload?.metadata.originIp; + default: + return undefined; } }; diff --git a/gui/src/components/map/map-component.tsx b/gui/src/components/map/map-component.tsx index b64a8261..5d3636c5 100644 --- a/gui/src/components/map/map-component.tsx +++ b/gui/src/components/map/map-component.tsx @@ -292,6 +292,7 @@ type MapProps = { intersectionId: number | undefined; roadRegulatorId: number | undefined; loadOnNull?: boolean; + timeFilterBsms?: boolean; }; const MapTab = forwardRef( @@ -313,7 +314,7 @@ const MapTab = forwardRef( heading?: number; animationDurationMs?: number; }) => { - console.log("Centering map on point", latitude, longitude); + console.debug("Centering map on point", latitude, longitude); if (mapRef.current) { mapRef.current.flyTo({ center: [longitude, latitude], @@ -323,28 +324,6 @@ const MapTab = forwardRef( }); } }, - setRenderedMapData: (mapMessage: ProcessedMap) => { - const mapCoordinates: OdePosition3D = mapMessage?.properties.refPoint; - - setConnectingLanes(mapMessage.connectingLanesFeatureCollection); - const mapSignalGroupsLocal = parseMapSignalGroups(mapMessage); - setMapData(mapMessage); - setMapSpatTimes((prevValue) => ({ - ...prevValue, - mapTime: getTimestamp(mapMessage.properties.odeReceivedAt) / 1000, - })); - setMapSignalGroups(mapSignalGroupsLocal); - }, - setRenderedSpatData: (spatData: ProcessedSpat[]) => { - console.log("Rendering SPAT data", spatData?.length); - const spatSignalGroups = parseSpatSignalGroups(spatData); - setSpatSignalGroups(spatSignalGroups); - }, - setRenderedBsmData: (bsmData: OdeBsmData[]) => { - console.log("Rendering BSM data", bsmData?.length); - const bsmGeojson = parseBsmToGeojson(bsmData); - setBsmData(bsmGeojson); - }, })); const [queryParams, setQueryParams] = useState<{ @@ -874,12 +853,17 @@ const MapTab = forwardRef( queryParams.roadRegulatorId ); return; - } else if (queryParams.intersectionId === -1 && props.sourceDataType !== "exact") { - console.error("Intersection ID is -1. Not attempting to pull initial map data."); + } else if ( + queryParams.intersectionId === -1 && + (props.sourceDataType !== "exact" || (props.sourceData as { map: ProcessedMap[] })?.map?.length === 0) + ) { resetMapView(); - return; + if (props.sourceDataType !== "exact") { + console.log("Intersection ID is -1. Not attempting to pull initial map data."); + return; + } } - console.debug("Pulling Initial Data"); + console.log("Pulling Initial Data"); pullInitialDataAbortControllers.forEach((abortController) => abortController.abort()); let rawMap: ProcessedMap[] = []; let rawSpat: ProcessedSpat[] = []; @@ -979,7 +963,7 @@ const MapTab = forwardRef( })); setMapSignalGroups(mapSignalGroupsLocal); - if (importedMessageData == undefined) { + if (importedMessageData == undefined && props.sourceDataType != "exact") { // ######################### Retrieve SPAT Data ######################### let abortController = new AbortController(); setPullInitialDataAbortControllers((prevValue) => [...prevValue, abortController]); @@ -1060,9 +1044,9 @@ const MapTab = forwardRef( setSpatSignalGroups(spatSignalGroupsLocal); // ######################### BSMs ######################### - abortController = new AbortController(); - setPullInitialDataAbortControllers((prevValue) => [...prevValue, abortController]); if (!importedMessageData && props.sourceDataType != "exact") { + abortController = new AbortController(); + setPullInitialDataAbortControllers((prevValue) => [...prevValue, abortController]); const rawBsmPromise = MessageMonitorApi.getBsmMessages({ token: session?.accessToken, vehicleId: queryParams.vehicleId, @@ -1197,7 +1181,6 @@ const MapTab = forwardRef( setFilteredSurroundingNotifications([]); setBsmData({ type: "FeatureCollection", features: [] }); setCurrentBsms({ type: "FeatureCollection", features: [] }); - console.log("1191 setCurrentBsms", { type: "FeatureCollection", features: [] }); setMapSpatTimes({ mapTime: 0, spatTime: 0 }); setRawData({}); setSliderValue(0); @@ -1343,7 +1326,6 @@ const MapTab = forwardRef( }; setBsmData(currentBsmGeojson); setRawData((prevValue) => ({ ...prevValue, bsm: currentBsmGeojson })); - console.debug("BSM RENDER TIME:", Date.now() - start, "ms"); return currentBsmGeojson; }; @@ -1391,13 +1373,11 @@ const MapTab = forwardRef( clearTimeout(loadInitialDataTimeoutId); } setLoadInitialdataTimeoutId(setTimeout(pullInitialData, 500)); - }, [queryParams]); + }, [queryParams, props.sourceData]); useEffect(() => { - if (props.sourceDataType == "exact") { - // In "exact" mode, always show all BSMs. Timestamps are meaningless. + if (props.timeFilterBsms == false) { setCurrentBsms(bsmData); - console.log("1391 setCurrentBsms", bsmData); } if (!mapSignalGroups || !spatSignalGroups) { console.debug("BSM Loading: No map or SPAT data", mapSignalGroups, spatSignalGroups); @@ -1427,7 +1407,7 @@ const MapTab = forwardRef( setSignalStateData(undefined); } - if (props.sourceDataType !== "exact") { + if (props.timeFilterBsms == false) { // retrieve filtered BSMs const filteredBsms: BsmFeature[] = bsmData?.features?.filter( (feature) => @@ -1461,7 +1441,6 @@ const MapTab = forwardRef( } } setCurrentBsms({ ...bsmData, features: lastBsms }); - console.log("1455 setCurrentBsms", { ...bsmData, features: lastBsms }); } const filteredEvents: MessageMonitor.Event[] = surroundingEvents.filter( @@ -1562,7 +1541,7 @@ const MapTab = forwardRef( let protocols = ["v10.stomp", "v11.stomp"]; protocols.push(token); const url = `${publicRuntimeConfig.API_WS_URL}/stomp`; - console.debug("Connecting to STOMP endpoint: " + url + " with token: " + token); + console.debug("Connecting to STOMP endpoint: " + url); // Stomp Client Documentation: https://stomp-js.github.io/stomp-websocket/codo/extra/docs-src/Usage.md.html let client = Stomp.client(url, protocols); @@ -1861,7 +1840,7 @@ const MapTab = forwardRef( mapStyle={mbStyle as mapboxgl.Style} onLoad={(e: mapboxgl.MapboxEvent) => { const map = e.target; - console.log("MAP LOADED", mapRef.current, map, e.target); + console.debug("MAP LOADED", mapRef.current, map, e.target); if (!map) return; const images = [ "traffic-light-icon-unknown", @@ -1878,7 +1857,7 @@ const MapTab = forwardRef( console.error("Error loading image:", image_name, error, image, map.hasImage(image_name)); return; } - console.log("MAP IMAGE", image_name, map.hasImage(image_name)); + console.debug("MAP IMAGE", image_name, map.hasImage(image_name)); if (!map.hasImage(image_name)) map.addImage(image_name, image); }); } diff --git a/gui/src/pages/decoder.tsx b/gui/src/pages/decoder.tsx index 179aef2e..911d1d3a 100644 --- a/gui/src/pages/decoder.tsx +++ b/gui/src/pages/decoder.tsx @@ -20,6 +20,8 @@ const DecoderPage = () => { const [selectedBsms, setSelectedBsms] = useState([] as string[]); const mapRef = useRef(null); + const [currentBsms, setCurrentBsms] = useState([] as OdeBsmData[]); + console.log("Data", data); useEffect(() => { @@ -62,6 +64,7 @@ const DecoderPage = () => { if (type == "BSM") { setSelectedBsms((prevBsms) => [...prevBsms, id]); } + console.log("Response", response); setData((prevData) => { return { ...prevData, @@ -69,13 +72,28 @@ const DecoderPage = () => { ...prevData[id], decodedResponse: response, timestamp: getTimestampFromType(type, response), - status: text == "" ? "NOT_STARTED" : response == undefined ? "ERROR" : "COMPLETED", + status: text == "" ? "NOT_STARTED" : response?.decodeErrors !== "" ? "ERROR" : "COMPLETED", }, }; }); }); + prevData = { + ...prevData, + [id]: { + id: id, + type: type, + status: "IN_PROGRESS", + selected: false, + isGreyedOut: false, + text: text, + decodedResponse: undefined, + }, + }; let newEntry = {}; - if (prevData[id].text != undefined) { + if ( + prevData[id].text != undefined && + Object.values(prevData).find((v) => v.type == type && v.text == "") == undefined + ) { let newId = uuidv4(); newEntry[newId] = { id: newId, @@ -88,17 +106,8 @@ const DecoderPage = () => { }; } return { - ...prevData, ...newEntry, - [id]: { - id: id, - type: type, - status: "IN_PROGRESS", - selected: false, - isGreyedOut: false, - text: text, - decodedResponse: undefined, - }, + ...prevData, }; }); }; @@ -213,6 +222,14 @@ const DecoderPage = () => { return (selectedMapMessage?.rsuIp === undefined || rsuIp !== selectedMapMessage?.rsuIp) && rsuIp != ""; }; + useEffect(() => { + const newBsmData = Object.values(data) + .filter((v) => v.type === "BSM" && v.status === "COMPLETED" && selectedBsms.includes(v.id)) + .map((v) => v.decodedResponse?.bsm); + setCurrentBsms(newBsmData.filter((v) => v !== undefined) as OdeBsmData[]); + console.log("Current BSMs", newBsmData.length); + }, [data, selectedBsms]); + return ( <> @@ -264,9 +281,7 @@ const DecoderPage = () => { v.type === "SPAT" && v.status == "COMPLETED" && !isGreyedOut(getIntersectionId(v.decodedResponse)) ) .map((v) => v.decodedResponse?.processedSpat!), - bsm: Object.values(data) - .filter((v) => v.type === "BSM" && v.status == "COMPLETED" && selectedBsms.includes(v.id)) - .map((v) => v.decodedResponse?.bsm!), + bsm: currentBsms, }} sourceDataType={"exact"} intersectionId={-1}