From bba48ae84b4b4b14c11cc8f72e2873549cf6a9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Tue, 16 Jul 2024 15:03:28 +0200 Subject: [PATCH] Add missing error handling in frontend --- frontend/src/App.tsx | 36 ++++----- .../src/components/Contexts/AlertContext.tsx | 19 ++++- .../Contexts/InstallationContext.tsx | 80 ++++++++++++++----- .../Contexts/MissionControlContext.tsx | 57 ++++++++++++- .../Contexts/MissionDefinitionsContext.tsx | 16 +++- .../Contexts/MissionRunsContext.tsx | 24 +++++- .../src/components/Contexts/RobotContext.tsx | 20 ++++- .../AssetSelectionPage/AssetSelectionPage.tsx | 23 +++++- .../FrontPage/MissionOverview/StopDialogs.tsx | 22 ++++- .../MissionDefinitionPage.tsx | 20 ++++- .../MissionHistoryPage/MissionHistoryView.tsx | 31 +++++-- .../Pages/MissionPage/MissionPage.tsx | 31 +++++-- .../components/Pages/RobotPage/RobotPage.tsx | 14 +++- frontend/src/language/en.json | 18 ++++- frontend/src/language/no.json | 18 ++++- 15 files changed, 353 insertions(+), 76 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7dc01977a..394c647f2 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -28,15 +28,15 @@ if (config.AI_CONNECTION_STRING.length > 0) { const App = () => ( - - - - - - - - - + + + + + + + + +
@@ -49,15 +49,15 @@ const App = () => ( - - - - - - - - - + + + + + + + + + ) diff --git a/frontend/src/components/Contexts/AlertContext.tsx b/frontend/src/components/Contexts/AlertContext.tsx index e90f789e9..dee860cfe 100644 --- a/frontend/src/components/Contexts/AlertContext.tsx +++ b/frontend/src/components/Contexts/AlertContext.tsx @@ -13,6 +13,8 @@ import { FailedAlertContent } from 'components/Alerts/FailedAlertContent' import { convertUTCDateToLocalDate } from 'utils/StringFormatting' import { AlertCategory } from 'components/Alerts/AlertsBanner' import { SafeZoneAlertContent } from 'components/Alerts/SafeZoneAlert' +import { useLanguageContext } from './LanguageContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' export enum AlertType { MissionFail, @@ -60,6 +62,7 @@ export const AlertProvider: FC = ({ children }) => { const [blockedRobotNames, setBlockedRobotNames] = useState([]) const { registerEvent, connectionReady } = useSignalRContext() const { installationCode } = useInstallationContext() + const { TranslateText } = useLanguageContext() const { enabledRobots } = useRobotContext() const pageSize: number = 100 @@ -108,8 +111,8 @@ export const AlertProvider: FC = ({ children }) => { useEffect(() => { const updateRecentFailedMissions = () => { const lastDismissTime: Date = getLastDismissalTime() - BackendAPICaller.getMissionRuns({ statuses: [MissionStatus.Failed], pageSize: pageSize }).then( - (missions) => { + BackendAPICaller.getMissionRuns({ statuses: [MissionStatus.Failed], pageSize: pageSize }) + .then((missions) => { const newRecentFailedMissions = missions.content.filter( (m) => convertUTCDateToLocalDate(new Date(m.endTime!)) > lastDismissTime && @@ -118,8 +121,16 @@ export const AlertProvider: FC = ({ children }) => { ) if (newRecentFailedMissions.length > 0) setNewFailedMissions(newRecentFailedMissions) setRecentFailedMissions(newRecentFailedMissions) - } - ) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) } if (!recentFailedMissions || recentFailedMissions.length === 0) updateRecentFailedMissions() // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/frontend/src/components/Contexts/InstallationContext.tsx b/frontend/src/components/Contexts/InstallationContext.tsx index a5c71fa71..afda7912e 100644 --- a/frontend/src/components/Contexts/InstallationContext.tsx +++ b/frontend/src/components/Contexts/InstallationContext.tsx @@ -4,6 +4,10 @@ import { EchoPlantInfo } from 'models/EchoMission' import { Deck } from 'models/Deck' import { SignalREventLabels, useSignalRContext } from './SignalRContext' import { Area } from 'models/Area' +import { useLanguageContext } from './LanguageContext' +import { AlertType, useAlertContext } from './AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' interface IInstallationContext { installationCode: string @@ -37,6 +41,8 @@ export const InstallationContext = createContext(defaultIn export const InstallationProvider: FC = ({ children }) => { const { registerEvent, connectionReady } = useSignalRContext() + const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() const [allPlantsMap, setAllPlantsMap] = useState>(new Map()) const [installationName, setInstallationName] = useState( window.localStorage.getItem('installationName') || '' @@ -47,31 +53,67 @@ export const InstallationProvider: FC = ({ children }) => { const installationCode = (allPlantsMap.get(installationName) || '').toUpperCase() useEffect(() => { - BackendAPICaller.getEchoPlantInfo().then((response: EchoPlantInfo[]) => { - const mapping = mapInstallationCodeToName(response) - setAllPlantsMap(mapping) - }) + BackendAPICaller.getEchoPlantInfo() + .then((response: EchoPlantInfo[]) => { + const mapping = mapInstallationCodeToName(response) + setAllPlantsMap(mapping) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) useEffect(() => { if (installationCode) - BackendAPICaller.getDecksByInstallationCode(installationCode).then((decks: Deck[]) => { - setInstallationDecks(decks) - decks.forEach((deck) => - BackendAPICaller.getAreasByDeckId(deck.id).then((areas) => - setInstallationAreas((oldAreas) => { - let areasCopy = [...oldAreas] - let newAreas: Area[] = [] - areas.forEach((area) => { - const indexBeUpdated = areasCopy.findIndex((a) => a.id === area.id) - if (indexBeUpdated === -1) newAreas = [...newAreas, area] - else areasCopy[indexBeUpdated] = area + BackendAPICaller.getDecksByInstallationCode(installationCode) + .then((decks: Deck[]) => { + setInstallationDecks(decks) + decks.forEach((deck) => + BackendAPICaller.getAreasByDeckId(deck.id) + .then((areas) => + setInstallationAreas((oldAreas) => { + let areasCopy = [...oldAreas] + let newAreas: Area[] = [] + areas.forEach((area) => { + const indexBeUpdated = areasCopy.findIndex((a) => a.id === area.id) + if (indexBeUpdated === -1) newAreas = [...newAreas, area] + else areasCopy[indexBeUpdated] = area + }) + return areasCopy.concat(newAreas) + }) + ) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) }) - return areasCopy.concat(newAreas) - }) ) - ) - }) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [installationCode]) useEffect(() => { diff --git a/frontend/src/components/Contexts/MissionControlContext.tsx b/frontend/src/components/Contexts/MissionControlContext.tsx index 1013f4a8a..2077ee1bb 100644 --- a/frontend/src/components/Contexts/MissionControlContext.tsx +++ b/frontend/src/components/Contexts/MissionControlContext.tsx @@ -1,6 +1,11 @@ import { createContext, useContext, useState, FC } from 'react' import { BackendAPICaller } from 'api/ApiCaller' import { MissionStatusRequest } from 'components/Pages/FrontPage/MissionOverview/StopDialogs' +import { AlertType, useAlertContext } from './AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' +import { useLanguageContext } from './LanguageContext' +import { useRobotContext } from './RobotContext' interface IMissionControlState { isRobotMissionWaitingForResponseDict: { [robotId: string]: boolean } @@ -26,6 +31,9 @@ const defaultManagementState: IMissionControlState = { } export const MissionControlProvider: FC = ({ children }) => { + const { TranslateText } = useLanguageContext() + const { enabledRobots } = useRobotContext() + const { setAlert } = useAlertContext() const [missionControlState, setMissionControlState] = useState(defaultManagementState) const setIsWaitingForResponse = (robotId: string, isWaiting: boolean) => { @@ -35,20 +43,63 @@ export const MissionControlProvider: FC = ({ children }) => { } const updateRobotMissionState = (newState: MissionStatusRequest, robotId: string) => { + const robot = enabledRobots.find((r) => r.id === robotId) + if (!robot) { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + return + } + + const robotName = robot!.name! switch (newState) { case MissionStatusRequest.Pause: { setIsWaitingForResponse(robotId, true) - BackendAPICaller.pauseMission(robotId).then((_) => setIsWaitingForResponse(robotId, false)) + BackendAPICaller.pauseMission(robotId) + .then((_) => setIsWaitingForResponse(robotId, false)) + .catch((_) => + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + ) break } case MissionStatusRequest.Resume: { setIsWaitingForResponse(robotId, true) - BackendAPICaller.resumeMission(robotId).then((_) => setIsWaitingForResponse(robotId, false)) + BackendAPICaller.resumeMission(robotId) + .then((_) => setIsWaitingForResponse(robotId, false)) + .catch((_) => + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + ) break } case MissionStatusRequest.Stop: { setIsWaitingForResponse(robotId, true) - BackendAPICaller.stopMission(robotId).then((_) => setIsWaitingForResponse(robotId, false)) + BackendAPICaller.stopMission(robotId) + .then((_) => setIsWaitingForResponse(robotId, false)) + .catch((_) => + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + ) break } } diff --git a/frontend/src/components/Contexts/MissionDefinitionsContext.tsx b/frontend/src/components/Contexts/MissionDefinitionsContext.tsx index 8075f0a47..bad68f20d 100644 --- a/frontend/src/components/Contexts/MissionDefinitionsContext.tsx +++ b/frontend/src/components/Contexts/MissionDefinitionsContext.tsx @@ -3,6 +3,10 @@ import { BackendAPICaller } from 'api/ApiCaller' import { SignalREventLabels, useSignalRContext } from './SignalRContext' import { CondensedMissionDefinition } from 'models/MissionDefinition' import { useInstallationContext } from './InstallationContext' +import { useLanguageContext } from './LanguageContext' +import { AlertType, useAlertContext } from './AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' interface IMissionDefinitionsContext { missionDefinitions: CondensedMissionDefinition[] @@ -43,6 +47,8 @@ export const useMissionDefinitions = (): IMissionDefinitionsContext => { const [missionDefinitions, setMissionDefinitions] = useState([]) const { registerEvent, connectionReady } = useSignalRContext() const { installationCode } = useInstallationContext() + const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() useEffect(() => { if (connectionReady) { @@ -78,8 +84,16 @@ export const useMissionDefinitions = (): IMissionDefinitionsContext => { installationCode: installationCode, pageSize: 100, orderBy: 'InstallationCode installationCode', + }).catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) }) - setMissionDefinitions(missionDefinitionsInInstallation) + setMissionDefinitions(missionDefinitionsInInstallation ?? []) } if (BackendAPICaller.accessToken) fetchAndUpdateMissionDefinitions() // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/frontend/src/components/Contexts/MissionRunsContext.tsx b/frontend/src/components/Contexts/MissionRunsContext.tsx index 68c146ff1..be79d5cc4 100644 --- a/frontend/src/components/Contexts/MissionRunsContext.tsx +++ b/frontend/src/components/Contexts/MissionRunsContext.tsx @@ -3,6 +3,10 @@ import { Mission, MissionStatus } from 'models/Mission' import { BackendAPICaller } from 'api/ApiCaller' import { SignalREventLabels, useSignalRContext } from './SignalRContext' import { TaskStatus } from 'models/Task' +import { useLanguageContext } from './LanguageContext' +import { AlertType, useAlertContext } from './AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' const upsertMissionList = (list: Mission[], mission: Mission) => { let newMissionList = [...list] @@ -76,6 +80,8 @@ export const useMissionRuns = (): IMissionRunsContext => { const [missionQueue, setMissionQueue] = useState([]) const [loadingMissionSet, setLoadingMissionSet] = useState>(new Set()) const { registerEvent, connectionReady } = useSignalRContext() + const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() useEffect(() => { if (connectionReady) { @@ -123,15 +129,29 @@ export const useMissionRuns = (): IMissionRunsContext => { statuses: [MissionStatus.Ongoing, MissionStatus.Paused], pageSize: 100, orderBy: 'StartTime desc', + }).catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) }) - setOngoingMissions(ongoing) + + setOngoingMissions(ongoing ?? []) const queue = await fetchMissionRuns({ statuses: [MissionStatus.Pending], pageSize: 100, orderBy: 'DesiredStartTime', + }).catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) }) - setMissionQueue(queue) + + setMissionQueue(queue ?? []) } if (BackendAPICaller.accessToken) fetchAndUpdateMissions() // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/frontend/src/components/Contexts/RobotContext.tsx b/frontend/src/components/Contexts/RobotContext.tsx index 51f4afb8c..f0b4f8a13 100644 --- a/frontend/src/components/Contexts/RobotContext.tsx +++ b/frontend/src/components/Contexts/RobotContext.tsx @@ -2,6 +2,10 @@ import { createContext, useContext, useState, FC, useEffect } from 'react' import { BackendAPICaller } from 'api/ApiCaller' import { Robot } from 'models/Robot' import { SignalREventLabels, useSignalRContext } from './SignalRContext' +import { useLanguageContext } from './LanguageContext' +import { AlertType, useAlertContext } from './AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' const upsertRobotList = (list: Robot[], mission: Robot) => { let newList = [...list] @@ -28,6 +32,8 @@ export const RobotContext = createContext(defaultRobotState) export const RobotProvider: FC = ({ children }) => { const [enabledRobots, setEnabledRobots] = useState(defaultRobotState.enabledRobots) const { registerEvent, connectionReady } = useSignalRContext() + const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() useEffect(() => { if (connectionReady) { @@ -66,9 +72,17 @@ export const RobotProvider: FC = ({ children }) => { useEffect(() => { if (!enabledRobots || enabledRobots.length === 0) - BackendAPICaller.getEnabledRobots().then((robots) => { - setEnabledRobots(robots) - }) + BackendAPICaller.getEnabledRobots() + .then((robots) => { + setEnabledRobots(robots) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) // eslint-disable-next-line react-hooks/exhaustive-deps }, []) diff --git a/frontend/src/components/Pages/AssetSelectionPage/AssetSelectionPage.tsx b/frontend/src/components/Pages/AssetSelectionPage/AssetSelectionPage.tsx index 0880d4927..752908397 100644 --- a/frontend/src/components/Pages/AssetSelectionPage/AssetSelectionPage.tsx +++ b/frontend/src/components/Pages/AssetSelectionPage/AssetSelectionPage.tsx @@ -11,6 +11,9 @@ import { BackendAPICaller } from 'api/ApiCaller' import { EchoPlantInfo } from 'models/EchoMission' import { Header } from 'components/Header/Header' import { config } from 'config' +import { AlertType, useAlertContext } from 'components/Contexts/AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' const Centered = styled.div` display: flex; @@ -71,6 +74,7 @@ export const AssetSelectionPage = () => { const InstallationPicker = () => { const { installationName, switchInstallation } = useInstallationContext() const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() const [allPlantsMap, setAllPlantsMap] = useState>(new Map()) const [selectedInstallation, setSelectedInstallation] = useState(installationName) const [showActivePlants, setShowActivePlants] = useState(true) @@ -86,11 +90,22 @@ const InstallationPicker = () => { const plantPromise = showActivePlants ? BackendAPICaller.getActivePlants() : BackendAPICaller.getEchoPlantInfo() - plantPromise.then(async (response: EchoPlantInfo[]) => { - const mapping = mapInstallationCodeToName(response) - setAllPlantsMap(mapping) - }) + plantPromise + .then(async (response: EchoPlantInfo[]) => { + const mapping = mapInstallationCodeToName(response) + setAllPlantsMap(mapping) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [showActivePlants, updateListOfActivePlants]) return ( diff --git a/frontend/src/components/Pages/FrontPage/MissionOverview/StopDialogs.tsx b/frontend/src/components/Pages/FrontPage/MissionOverview/StopDialogs.tsx index 24c42eaaf..aa0cc6a7d 100644 --- a/frontend/src/components/Pages/FrontPage/MissionOverview/StopDialogs.tsx +++ b/frontend/src/components/Pages/FrontPage/MissionOverview/StopDialogs.tsx @@ -9,6 +9,9 @@ import { BackendAPICaller } from 'api/ApiCaller' import { useInstallationContext } from 'components/Contexts/InstallationContext' import { useSafeZoneContext } from 'components/Contexts/SafeZoneContext' import { TaskType } from 'models/Task' +import { AlertType, useAlertContext } from 'components/Contexts/AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' const StyledDisplayButtons = styled.div` display: flex; @@ -139,6 +142,7 @@ export const StopRobotDialog = (): JSX.Element => { const { safeZoneStatus } = useSafeZoneContext() const { TranslateText } = useLanguageContext() const { installationCode } = useInstallationContext() + const { setAlert } = useAlertContext() const openDialog = async () => { setIsStopRobotDialogOpen(true) @@ -149,13 +153,27 @@ export const StopRobotDialog = (): JSX.Element => { } const stopAll = () => { - BackendAPICaller.sendRobotsToSafePosition(installationCode) + BackendAPICaller.sendRobotsToSafePosition(installationCode).catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) closeDialog() return } const resetRobots = () => { - BackendAPICaller.clearEmergencyState(installationCode) + BackendAPICaller.clearEmergencyState(installationCode).catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) closeDialog() } diff --git a/frontend/src/components/Pages/MissionDefinitionPage/MissionDefinitionPage.tsx b/frontend/src/components/Pages/MissionDefinitionPage/MissionDefinitionPage.tsx index e64b0eb47..fd71dd446 100644 --- a/frontend/src/components/Pages/MissionDefinitionPage/MissionDefinitionPage.tsx +++ b/frontend/src/components/Pages/MissionDefinitionPage/MissionDefinitionPage.tsx @@ -15,6 +15,9 @@ import { StyledDict } from './MissionDefinitionStyledComponents' import { useMissionDefinitionsContext } from 'components/Contexts/MissionDefinitionsContext' import { StyledPage } from 'components/Styles/StyledComponents' import styled from 'styled-components' +import { AlertType, useAlertContext } from 'components/Contexts/AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' const StyledDictCard = styled(StyledDict.Card)` box-shadow: ${tokens.elevation.raised}; @@ -146,6 +149,7 @@ const MissionDefinitionEditDialog = ({ isDeprecated: false, } const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() const navigate = useNavigate() const [form, setForm] = useState(defaultMissionDefinitionForm) @@ -175,10 +179,18 @@ const MissionDefinitionEditDialog = ({ const handleSubmit = () => { const daysAndHours = getDayAndHoursFromInspectionFrequency(form.inspectionFrequency) if (daysAndHours[0] === 0 && daysAndHours[1] === 0) form.inspectionFrequency = undefined - BackendAPICaller.updateMissionDefinition(missionDefinition.id, form).then((missionDefinition) => { - closeEditDialog() - if (missionDefinition.isDeprecated) navigate(`${config.FRONTEND_BASE_ROUTE}/FrontPage`) - }) + BackendAPICaller.updateMissionDefinition(missionDefinition.id, form) + .then((missionDefinition) => { + closeEditDialog() + if (missionDefinition.isDeprecated) navigate(`${config.FRONTEND_BASE_ROUTE}/FrontPage`) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) } const inspectionFrequency = getDayAndHoursFromInspectionFrequency(form.inspectionFrequency) diff --git a/frontend/src/components/Pages/MissionHistoryPage/MissionHistoryView.tsx b/frontend/src/components/Pages/MissionHistoryPage/MissionHistoryView.tsx index 36cc9647b..baf3625d0 100644 --- a/frontend/src/components/Pages/MissionHistoryPage/MissionHistoryView.tsx +++ b/frontend/src/components/Pages/MissionHistoryPage/MissionHistoryView.tsx @@ -12,6 +12,9 @@ import { FilterSection } from './FilterSection' import { InspectionType } from 'models/Inspection' import { tokens } from '@equinor/eds-tokens' import { SmallScreenInfoText } from 'utils/InfoText' +import { AlertType, useAlertContext } from 'components/Contexts/AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' enum InspectionTableColumns { StatusShort = 'StatusShort', @@ -101,6 +104,7 @@ export const MissionHistoryView = ({ refreshInterval }: RefreshProps) => { const { TranslateText } = useLanguageContext() const { page, switchPage, filterState, filterIsSet, filterFunctions, filterError, clearFilterError } = useMissionFilterContext() + const { setAlert } = useAlertContext() const [filteredMissions, setFilteredMissions] = useState([]) const [paginationDetails, setPaginationDetails] = useState() const [isLoading, setIsLoading] = useState(true) @@ -161,15 +165,26 @@ export const MissionHistoryView = ({ refreshInterval }: RefreshProps) => { pageSize: pageSize, pageNumber: page ?? 1, orderBy: 'EndTime desc, Name', - }).then((paginatedMissions) => { - setFilteredMissions(paginatedMissions.content) - setPaginationDetails(paginatedMissions.pagination) - if (page > paginatedMissions.pagination.TotalPages && paginatedMissions.pagination.TotalPages > 0) { - switchPage(paginatedMissions.pagination.TotalPages) - setIsResettingPage(true) - } - setIsLoading(false) }) + .then((paginatedMissions) => { + setFilteredMissions(paginatedMissions.content) + setPaginationDetails(paginatedMissions.pagination) + if (page > paginatedMissions.pagination.TotalPages && paginatedMissions.pagination.TotalPages > 0) { + switchPage(paginatedMissions.pagination.TotalPages) + setIsResettingPage(true) + } + setIsLoading(false) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [page, pageSize, switchPage, filterFunctions]) useEffect(() => { diff --git a/frontend/src/components/Pages/MissionPage/MissionPage.tsx b/frontend/src/components/Pages/MissionPage/MissionPage.tsx index 073bd01c7..2b0a50d80 100644 --- a/frontend/src/components/Pages/MissionPage/MissionPage.tsx +++ b/frontend/src/components/Pages/MissionPage/MissionPage.tsx @@ -11,6 +11,10 @@ import { MissionMapView } from './MapPosition/MissionMapView' import { BackendAPICaller } from 'api/ApiCaller' import { Header } from 'components/Header/Header' import { SignalREventLabels, useSignalRContext } from 'components/Contexts/SignalRContext' +import { AlertType, useAlertContext } from 'components/Contexts/AlertContext' +import { useLanguageContext } from 'components/Contexts/LanguageContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' const StyledMissionPage = styled.div` display: flex; @@ -35,6 +39,8 @@ const VideoStreamSection = styled.div` export const MissionPage = () => { const { missionId } = useParams() + const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() const [videoStreams, setVideoStreams] = useState([]) const [selectedMission, setSelectedMission] = useState() const { registerEvent, connectionReady } = useSignalRContext() @@ -51,13 +57,28 @@ export const MissionPage = () => { useEffect(() => { const updateVideoStreams = (mission: Mission) => - BackendAPICaller.getVideoStreamsByRobotId(mission.robot.id).then((streams) => setVideoStreams(streams)) + BackendAPICaller.getVideoStreamsByRobotId(mission.robot.id) + .then((streams) => setVideoStreams(streams)) + .catch((e) => { + console.warn(`Failed to get video stream with robot ID ${mission.robot.id}`) + }) if (missionId) - BackendAPICaller.getMissionRunById(missionId).then((mission) => { - setSelectedMission(mission) - updateVideoStreams(mission) - }) + BackendAPICaller.getMissionRunById(missionId) + .then((mission) => { + setSelectedMission(mission) + updateVideoStreams(mission) + }) + .catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [missionId]) return ( diff --git a/frontend/src/components/Pages/RobotPage/RobotPage.tsx b/frontend/src/components/Pages/RobotPage/RobotPage.tsx index 1ed895b59..028962842 100644 --- a/frontend/src/components/Pages/RobotPage/RobotPage.tsx +++ b/frontend/src/components/Pages/RobotPage/RobotPage.tsx @@ -15,6 +15,9 @@ import { RobotType } from 'models/RobotModel' import { useRobotContext } from 'components/Contexts/RobotContext' import { BackendAPICaller } from 'api/ApiCaller' import { StyledButton, StyledPage } from 'components/Styles/StyledComponents' +import { AlertType, useAlertContext } from 'components/Contexts/AlertContext' +import { FailedRequestAlertContent } from 'components/Alerts/FailedRequestAlert' +import { AlertCategory } from 'components/Alerts/AlertsBanner' const RobotArmMovementSection = styled.div` display: flex; @@ -53,6 +56,7 @@ const StatusContent = styled.div<{ $alignItems?: string }>` export const RobotPage = () => { const { TranslateText } = useLanguageContext() + const { setAlert } = useAlertContext() const { robotId } = useParams() const { enabledRobots } = useRobotContext() @@ -60,7 +64,15 @@ export const RobotPage = () => { const returnRobotToHome = () => { if (robotId) { - BackendAPICaller.returnRobotToHome(robotId) + BackendAPICaller.returnRobotToHome(robotId).catch((e) => { + setAlert( + AlertType.RequestFail, + , + AlertCategory.ERROR + ) + }) } } diff --git a/frontend/src/language/en.json b/frontend/src/language/en.json index 8b23260cd..cc05797bd 100644 --- a/frontend/src/language/en.json +++ b/frontend/src/language/en.json @@ -240,5 +240,21 @@ "Recommended pressure": "Recommended pressure is 67 mBar.", "Pressure": "Pressure", "Pressure limit": "Pressure limits [mBar]", - "Add to queue": "Add to queue" + "Add to queue": "Add to queue", + "Failed to pause mission on {0}": "Failed to pause mission on robot {0}", + "Failed to resume mission on {0}": "Failed to resume mission on robot {0}", + "Failed to stop mission on {0}": "Failed to stop mission on robot {0}", + "Unable to find robot with ID {0}": "Unable to find robot with ID {0}", + "Failed to find mission with ID {0}": "Failed to find mission with ID {0}", + "Failed to retrieve failed missions": "Failed to retrieve failed missions", + "Failed to retrieve robots": "Failed to retrieve robots", + "Failed to retrieve inspection plans": "Failed to retrieve inspection plan", + "Failed to retrieve installations from Echo": "Failed to retrieve installations from Echo", + "Failed to retrieve mission runs": "Failed to retrieve mission runs", + "Failed to retrieve areas on deck {0}": "Failed to retrieve areas on deck {0}", + "Failed to retrieve decks on installation {0}": "Failed to retrieve decks on installation {0}", + "Failed to send robots to a safe zone": "Failed to send robots to a safe zone", + "Failed to release robots from safe zone": "Failed to release robots from safe zone", + "Failed to send robot {0} home": "Failed to send robot {0} to starting position", + "Failed to update inspection": "Failed to update inspection" } diff --git a/frontend/src/language/no.json b/frontend/src/language/no.json index 13aaea2a4..80dbf4ca5 100644 --- a/frontend/src/language/no.json +++ b/frontend/src/language/no.json @@ -240,5 +240,21 @@ "Recommended pressure": "Anbefalt trykk er 67 mBar.", "Pressure": "Trykk", "Pressure limit": "Trykkgrenser [mBar]", - "Add to queue": "Legg til i kø" + "Add to queue": "Legg til i kø", + "Failed to pause mission on {0}": "Kunne ikke pause oppdrag på robot {0}", + "Failed to resume mission on {0}": "Kunne ikke fortsette oppdrag på robot {0}", + "Failed to stop mission on {0}": "Kunne ikke stanse oppdrag på robot {0}", + "Unable to find robot with ID {0}": "Kunne ikke finne robot med ID {0}", + "Failed to find mission with ID {0}": "Kunne ikke finne oppdrag med ID {0}", + "Failed to retrieve failed missions": "Kunne ikke hente mislykkede oppdrag", + "Failed to retrieve robots": "Kunne ikke hente liste over roboter", + "Failed to retrieve inspection plans": "Kunne ikke hente inspeksjonsplanen", + "Failed to retrieve installations from Echo": "Kunne ikke hente installasjoner fra Echo", + "Failed to retrieve mission runs": "Kunne ikke hente oppdrag", + "Failed to retrieve areas on deck {0}": "Kunne ikke hente området på deck {0}", + "Failed to retrieve decks on installation {0}": "Kunne ikke hente deck på installasjon {0}", + "Failed to send robots to a safe zone": "Kunne ikke sende roboter til trygg sone", + "Failed to release robots from safe zone": "Kunne ikke slippe roboter ut av trygg sone", + "Failed to send robot {0} home": "Kunne ikke sende robot {0} til startposisjon", + "Failed to update inspection": "Kunne ikke oppdatere inspeksjon" }