Skip to content

Commit

Permalink
Move mission queue to react context
Browse files Browse the repository at this point in the history
  • Loading branch information
andchiind committed Aug 8, 2023
1 parent ccf557a commit f564efe
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 51 deletions.
35 changes: 19 additions & 16 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,28 @@ import { FlotillaSite } from 'components/Pages/FlotillaSite'
import { LanguageProvider } from 'components/Contexts/LanguageContext'
import { MissionControlProvider } from 'components/Contexts/MissionControlContext'
import { MissionFilterProvider } from 'components/Contexts/MissionFilterContext'
import { MissionQueueProvider } from 'components/Contexts/MissionQueueContext'

function App() {
return (
<LanguageProvider>
<MissionControlProvider>
<>
<UnauthenticatedTemplate>
<div className="sign-in-page">
<SignInPage></SignInPage>
</div>
</UnauthenticatedTemplate>
<AuthenticatedTemplate>
<MissionFilterProvider>
<FlotillaSite />
</MissionFilterProvider>
</AuthenticatedTemplate>
</>
</MissionControlProvider>
</LanguageProvider>
<MissionQueueProvider>
<LanguageProvider>
<MissionControlProvider>
<>
<UnauthenticatedTemplate>
<div className="sign-in-page">
<SignInPage></SignInPage>
</div>
</UnauthenticatedTemplate>
<AuthenticatedTemplate>
<MissionFilterProvider>
<FlotillaSite />
</MissionFilterProvider>
</AuthenticatedTemplate>
</>
</MissionControlProvider>
</LanguageProvider>
</MissionQueueProvider>
)
}

Expand Down
21 changes: 9 additions & 12 deletions frontend/src/components/Contexts/MissionControlContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createContext, useContext, useState, FC } from 'react'
import { BackendAPICaller } from 'api/ApiCaller'
import { Mission } from 'models/Mission'
import { ControlButton } from 'components/Pages/FrontPage/MissionOverview/StopMissionDialog'
import { MissionStatusRequest } from 'components/Pages/FrontPage/MissionOverview/StopMissionDialog'

interface IMissionControlState {
isWaitingForResponse: boolean
Expand All @@ -13,14 +13,12 @@ interface Props {

export interface IMissionControlContext {
missionControlState: IMissionControlState
setIsWaitingForResponse: (isWaiting: boolean) => void
handleClick: (button: ControlButton, mission: Mission) => void
updateMissionState: (newState: MissionStatusRequest, mission: Mission) => void
}

const defaultMissionControlInterface = {
missionControlState: { isWaitingForResponse: false },
setIsWaitingForResponse: (isWaiting: boolean) => {},
handleClick: (button: ControlButton, mission: Mission) => {},
updateMissionState: (newState: MissionStatusRequest, mission: Mission) => {},
}

export const MissionControlContext = createContext<IMissionControlContext>(defaultMissionControlInterface)
Expand All @@ -35,19 +33,19 @@ export const MissionControlProvider: FC<Props> = ({ children }) => {
setMissionControlState({ isWaitingForResponse: isWaiting })
}

const handleClick = (button: ControlButton, mission: Mission) => {
switch (button) {
case ControlButton.Pause: {
const updateMissionState = (newState: MissionStatusRequest, mission: Mission) => {
switch (newState) {
case MissionStatusRequest.Pause: {
setIsWaitingForResponse(true)
BackendAPICaller.pauseMission(mission.robot.id).then((_) => setIsWaitingForResponse(false))
break
}
case ControlButton.Resume: {
case MissionStatusRequest.Resume: {
setIsWaitingForResponse(true)
BackendAPICaller.resumeMission(mission.robot.id).then((_) => setIsWaitingForResponse(false))
break
}
case ControlButton.Stop: {
case MissionStatusRequest.Stop: {
setIsWaitingForResponse(true)
BackendAPICaller.stopMission(mission.robot.id).then((_) => setIsWaitingForResponse(false))
break
Expand All @@ -59,8 +57,7 @@ export const MissionControlProvider: FC<Props> = ({ children }) => {
<MissionControlContext.Provider
value={{
missionControlState,
setIsWaitingForResponse,
handleClick,
updateMissionState,
}}
>
{children}
Expand Down
52 changes: 52 additions & 0 deletions frontend/src/components/Contexts/MissionQueueContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { createContext, FC, useContext, useEffect, useState } from 'react'
import { Mission, MissionStatus } from 'models/Mission'
import { refreshInterval } from 'components/Pages/FrontPage/FrontPage'
import { BackendAPICaller } from 'api/ApiCaller'

interface IMissionQueueContext {
missionQueue: Mission[]
}

interface Props {
children: React.ReactNode
}

const defaultMissionQueueInterface = {
missionQueue: [],
}

export const MissionQueueContext = createContext<IMissionQueueContext>(defaultMissionQueueInterface)

export const MissionQueueProvider: FC<Props> = ({ children }) => {
const missionPageSize = 100
const [missionQueue, setMissionQueue] = useState<Mission[]>(defaultMissionQueueInterface.missionQueue)

useEffect(() => {
const id = setInterval(() => {
BackendAPICaller.getMissionRuns({
statuses: [MissionStatus.Pending],
pageSize: missionPageSize,
orderBy: 'DesiredStartTime',
}).then((missions) => {
setMissionQueue(missions.content)
})
}, refreshInterval)
return () => clearInterval(id)
}, [refreshInterval])

// If we ever want a view which integrates the control of the
// current mission with the queue, then we could combine this
// context with MissionControlContext.tsx

return (
<MissionQueueContext.Provider
value={{
missionQueue,
}}
>
{children}
</MissionQueueContext.Provider>
)
}

export const useMissionQueueContext = () => useContext(MissionQueueContext)
2 changes: 2 additions & 0 deletions frontend/src/components/Pages/FrontPage/FrontPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export type RefreshProps = {
refreshInterval: number
}

export const refreshInterval = 1000

export function FrontPage() {
const refreshInterval = 1000

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import styled from 'styled-components'
import { Typography } from '@equinor/eds-core-react'
import { useLanguageContext } from 'components/Contexts/LanguageContext'
import { useMissionControlContext } from 'components/Contexts/MissionControlContext'
import { StopMissionDialog, ControlButton } from './StopMissionDialog'
import { StopMissionDialog, MissionStatusRequest } from './StopMissionDialog'

interface MissionProps {
mission: Mission
Expand All @@ -31,7 +31,7 @@ const checkIfTasksStarted = (tasks: Task[]): boolean => {

export function MissionControlButtons({ mission }: MissionProps) {
const { TranslateText } = useLanguageContext()
const { missionControlState, handleClick } = useMissionControlContext()
const { missionControlState, updateMissionState } = useMissionControlContext()

const renderControlIcon = (missionStatus: MissionStatus) => {
if (missionControlState.isWaitingForResponse) {
Expand All @@ -44,7 +44,10 @@ export function MissionControlButtons({ mission }: MissionProps) {
<Typography variant="caption">{TranslateText('Stop')}</Typography>
</ButtonText>
<ButtonText>
<Button variant="ghost_icon" onClick={() => handleClick(ControlButton.Pause, mission)}>
<Button
variant="ghost_icon"
onClick={() => updateMissionState(MissionStatusRequest.Pause, mission)}
>
<Icon
name={Icons.PauseButton}
style={{ color: tokens.colors.interactive.secondary__resting.rgba }}
Expand All @@ -63,7 +66,10 @@ export function MissionControlButtons({ mission }: MissionProps) {
<Typography variant="caption">{TranslateText('Stop')}</Typography>
</ButtonText>
<ButtonText>
<Button variant="ghost_icon" onClick={() => handleClick(ControlButton.Resume, mission)}>
<Button
variant="ghost_icon"
onClick={() => updateMissionState(MissionStatusRequest.Resume, mission)}
>
<Icon
name={Icons.PlayButton}
style={{ color: tokens.colors.interactive.secondary__resting.rgba }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styled from 'styled-components'
import { MissionQueueCard } from './MissionQueueCard'
import { BackendAPICaller } from 'api/ApiCaller'
import { useEffect, useState } from 'react'
import { Mission, MissionStatus } from 'models/Mission'
import { Mission } from 'models/Mission'
import { EmptyMissionQueuePlaceholder } from './NoMissionPlaceholder'
import { ScheduleMissionDialog } from './ScheduleMissionDialog'
import { Robot } from 'models/Robot'
Expand All @@ -12,6 +12,7 @@ import { useLanguageContext } from 'components/Contexts/LanguageContext'
import { useInstallationContext } from 'components/Contexts/InstallationContext'
import { CreateMissionButton } from './CreateMissionButton'
import { MissionDefinition } from 'models/MissionDefinition'
import { useMissionQueueContext } from 'components/Contexts/MissionQueueContext'

const StyledMissionView = styled.div`
display: grid;
Expand Down Expand Up @@ -40,8 +41,8 @@ const mapEchoMissionToString = (missions: MissionDefinition[]): Map<string, Miss

export function MissionQueueView({ refreshInterval }: RefreshProps) {
const { TranslateText } = useLanguageContext()
const missionPageSize = 100
const [missionQueue, setMissionQueue] = useState<Mission[]>([])
const { missionQueue } = useMissionQueueContext()

const [selectedEchoMissions, setSelectedEchoMissions] = useState<MissionDefinition[]>([])
const [selectedRobot, setSelectedRobot] = useState<Robot>()
const [echoMissions, setEchoMissions] = useState<Map<string, MissionDefinition>>(
Expand Down Expand Up @@ -102,19 +103,6 @@ export function MissionQueueView({ refreshInterval }: RefreshProps) {
return () => clearInterval(id)
}, [refreshInterval])

useEffect(() => {
const id = setInterval(() => {
BackendAPICaller.getMissionRuns({
statuses: [MissionStatus.Pending],
pageSize: missionPageSize,
orderBy: 'DesiredStartTime',
}).then((missions) => {
setMissionQueue(missions.content)
})
}, refreshInterval)
return () => clearInterval(id)
}, [refreshInterval])

useEffect(() => {
if (selectedRobot === undefined || selectedEchoMissions.length === 0) {
setScheduleButtonDisabled(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface MissionProps {
mission: Mission
}

export enum ControlButton {
export enum MissionStatusRequest {
Pause,
Stop,
Resume,
Expand All @@ -40,7 +40,7 @@ export const StopMissionDialog = ({ mission }: MissionProps): JSX.Element => {
const { TranslateText } = useLanguageContext()
const [isStopMissionDialogOpen, setIsStopMissionDialogOpen] = useState<boolean>(false)
const [missionId, setMissionId] = useState<string>()
const { handleClick } = useMissionControlContext()
const { updateMissionState } = useMissionControlContext()

const openDialog = () => {
setIsStopMissionDialogOpen(true)
Expand Down Expand Up @@ -91,7 +91,7 @@ export const StopMissionDialog = ({ mission }: MissionProps): JSX.Element => {
<Button
variant="contained"
color="danger"
onClick={() => handleClick(ControlButton.Stop, mission)}
onClick={() => updateMissionState(MissionStatusRequest.Stop, mission)}
>
{TranslateText('Stop mission')}
</Button>
Expand Down

0 comments on commit f564efe

Please sign in to comment.