Skip to content

Commit

Permalink
Add missing error handling in frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
andchiind committed Jul 18, 2024
1 parent 8a80fed commit bba48ae
Show file tree
Hide file tree
Showing 15 changed files with 353 additions and 76 deletions.
36 changes: 18 additions & 18 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ if (config.AI_CONNECTION_STRING.length > 0) {

const App = () => (
<AuthProvider>
<SignalRProvider>
<InstallationProvider>
<MissionDefinitionsProvider>
<RobotProvider>
<MissionRunsProvider>
<AlertProvider>
<SafeZoneProvider>
<MissionRunsProvider>
<LanguageProvider>
<LanguageProvider>
<SignalRProvider>
<InstallationProvider>
<MissionDefinitionsProvider>
<RobotProvider>
<MissionRunsProvider>
<AlertProvider>
<SafeZoneProvider>
<MissionRunsProvider>
<MissionControlProvider>
<UnauthenticatedTemplate>
<div className="sign-in-page">
Expand All @@ -49,15 +49,15 @@ const App = () => (
</MissionFilterProvider>
</AuthenticatedTemplate>
</MissionControlProvider>
</LanguageProvider>
</MissionRunsProvider>
</SafeZoneProvider>
</AlertProvider>
</MissionRunsProvider>
</RobotProvider>
</MissionDefinitionsProvider>
</InstallationProvider>
</SignalRProvider>
</MissionRunsProvider>
</SafeZoneProvider>
</AlertProvider>
</MissionRunsProvider>
</RobotProvider>
</MissionDefinitionsProvider>
</InstallationProvider>
</SignalRProvider>
</LanguageProvider>
</AuthProvider>
)

Expand Down
19 changes: 15 additions & 4 deletions frontend/src/components/Contexts/AlertContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -60,6 +62,7 @@ export const AlertProvider: FC<Props> = ({ children }) => {
const [blockedRobotNames, setBlockedRobotNames] = useState<string[]>([])
const { registerEvent, connectionReady } = useSignalRContext()
const { installationCode } = useInstallationContext()
const { TranslateText } = useLanguageContext()
const { enabledRobots } = useRobotContext()

const pageSize: number = 100
Expand Down Expand Up @@ -108,8 +111,8 @@ export const AlertProvider: FC<Props> = ({ 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 &&
Expand All @@ -118,8 +121,16 @@ export const AlertProvider: FC<Props> = ({ children }) => {
)
if (newRecentFailedMissions.length > 0) setNewFailedMissions(newRecentFailedMissions)
setRecentFailedMissions(newRecentFailedMissions)
}
)
})
.catch((e) => {
setAlert(
AlertType.RequestFail,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to retrieve failed missions')}
/>,
AlertCategory.ERROR
)
})
}
if (!recentFailedMissions || recentFailedMissions.length === 0) updateRecentFailedMissions()
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
80 changes: 61 additions & 19 deletions frontend/src/components/Contexts/InstallationContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -37,6 +41,8 @@ export const InstallationContext = createContext<IInstallationContext>(defaultIn

export const InstallationProvider: FC<Props> = ({ children }) => {
const { registerEvent, connectionReady } = useSignalRContext()
const { TranslateText } = useLanguageContext()
const { setAlert } = useAlertContext()
const [allPlantsMap, setAllPlantsMap] = useState<Map<string, string>>(new Map())
const [installationName, setInstallationName] = useState<string>(
window.localStorage.getItem('installationName') || ''
Expand All @@ -47,31 +53,67 @@ export const InstallationProvider: FC<Props> = ({ 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,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to retrieve installations from Echo')}
/>,
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,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to retrieve areas on deck {0}', [
deck.deckName,
])}
/>,
AlertCategory.ERROR
)
})
return areasCopy.concat(newAreas)
})
)
)
})
})
.catch((e) => {
setAlert(
AlertType.RequestFail,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to retrieve decks on installation {0}', [
installationCode,
])}
/>,
AlertCategory.ERROR
)
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [installationCode])

useEffect(() => {
Expand Down
57 changes: 54 additions & 3 deletions frontend/src/components/Contexts/MissionControlContext.tsx
Original file line number Diff line number Diff line change
@@ -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 }
Expand All @@ -26,6 +31,9 @@ const defaultManagementState: IMissionControlState = {
}

export const MissionControlProvider: FC<Props> = ({ children }) => {
const { TranslateText } = useLanguageContext()
const { enabledRobots } = useRobotContext()
const { setAlert } = useAlertContext()
const [missionControlState, setMissionControlState] = useState<IMissionControlState>(defaultManagementState)

const setIsWaitingForResponse = (robotId: string, isWaiting: boolean) => {
Expand All @@ -35,20 +43,63 @@ export const MissionControlProvider: FC<Props> = ({ children }) => {
}

const updateRobotMissionState = (newState: MissionStatusRequest, robotId: string) => {
const robot = enabledRobots.find((r) => r.id === robotId)
if (!robot) {
setAlert(
AlertType.RequestFail,
<FailedRequestAlertContent
translatedMessage={TranslateText('Unable to find robot with ID {0}', [robotId])}
/>,
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,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to pause mission on {0}', [robotName])}
/>,
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,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to resume mission on {0}', [robotName])}
/>,
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,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to stop mission on {0}', [robotName])}
/>,
AlertCategory.ERROR
)
)
break
}
}
Expand Down
16 changes: 15 additions & 1 deletion frontend/src/components/Contexts/MissionDefinitionsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down Expand Up @@ -43,6 +47,8 @@ export const useMissionDefinitions = (): IMissionDefinitionsContext => {
const [missionDefinitions, setMissionDefinitions] = useState<CondensedMissionDefinition[]>([])
const { registerEvent, connectionReady } = useSignalRContext()
const { installationCode } = useInstallationContext()
const { TranslateText } = useLanguageContext()
const { setAlert } = useAlertContext()

useEffect(() => {
if (connectionReady) {
Expand Down Expand Up @@ -78,8 +84,16 @@ export const useMissionDefinitions = (): IMissionDefinitionsContext => {
installationCode: installationCode,
pageSize: 100,
orderBy: 'InstallationCode installationCode',
}).catch((e) => {
setAlert(
AlertType.RequestFail,
<FailedRequestAlertContent
translatedMessage={TranslateText('Failed to retrieve inspection plans')}
/>,
AlertCategory.ERROR
)
})
setMissionDefinitions(missionDefinitionsInInstallation)
setMissionDefinitions(missionDefinitionsInInstallation ?? [])
}
if (BackendAPICaller.accessToken) fetchAndUpdateMissionDefinitions()
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
24 changes: 22 additions & 2 deletions frontend/src/components/Contexts/MissionRunsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -76,6 +80,8 @@ export const useMissionRuns = (): IMissionRunsContext => {
const [missionQueue, setMissionQueue] = useState<Mission[]>([])
const [loadingMissionSet, setLoadingMissionSet] = useState<Set<string>>(new Set())
const { registerEvent, connectionReady } = useSignalRContext()
const { TranslateText } = useLanguageContext()
const { setAlert } = useAlertContext()

useEffect(() => {
if (connectionReady) {
Expand Down Expand Up @@ -123,15 +129,29 @@ export const useMissionRuns = (): IMissionRunsContext => {
statuses: [MissionStatus.Ongoing, MissionStatus.Paused],
pageSize: 100,
orderBy: 'StartTime desc',
}).catch((e) => {
setAlert(
AlertType.RequestFail,
<FailedRequestAlertContent translatedMessage={TranslateText('Failed to retrieve mission runs')} />,
AlertCategory.ERROR
)
})
setOngoingMissions(ongoing)

setOngoingMissions(ongoing ?? [])

const queue = await fetchMissionRuns({
statuses: [MissionStatus.Pending],
pageSize: 100,
orderBy: 'DesiredStartTime',
}).catch((e) => {
setAlert(
AlertType.RequestFail,
<FailedRequestAlertContent translatedMessage={TranslateText('Failed to retrieve mission runs')} />,
AlertCategory.ERROR
)
})
setMissionQueue(queue)

setMissionQueue(queue ?? [])
}
if (BackendAPICaller.accessToken) fetchAndUpdateMissions()
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
Loading

0 comments on commit bba48ae

Please sign in to comment.