Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement robot specific stop button #1799

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useLanguageContext } from 'components/Contexts/LanguageContext'
import { useMissionControlContext } from 'components/Contexts/MissionControlContext'
import { StopMissionDialog, MissionStatusRequest } from 'components/Pages/FrontPage/MissionOverview/StopDialogs'
import { TaskType } from 'models/Task'
import { useState } from 'react'

interface MissionControlButtonsProps {
missionName: string
Expand Down Expand Up @@ -71,12 +72,29 @@ export const MissionControlButtons = ({
const OngoingMissionButton = ({ missionName, robotId, missionTaskType }: MissionProps) => {
const { TranslateText } = useLanguageContext()
const { updateRobotMissionState } = useMissionControlContext()
const [isDialogOpen, setIsDialogOpen] = useState(false)
const toggleStopMissionDialog = () => {
setIsDialogOpen(!isDialogOpen)
}

return (
<>
<ButtonStyle>
<ButtonText>
<StopMissionDialog missionName={missionName} robotId={robotId} missionTaskType={missionTaskType} />
<Button variant="ghost_icon" onClick={toggleStopMissionDialog}>
<Icon
name={Icons.StopButton}
style={{ color: tokens.colors.interactive.secondary__resting.rgba }}
size={40}
/>
<StopMissionDialog
missionName={missionName}
robotId={robotId}
missionTaskType={missionTaskType}
isStopMissionDialogOpen={isDialogOpen}
toggleDialog={toggleStopMissionDialog}
/>
</Button>
<Typography variant="caption">{TranslateText('Stop')}</Typography>
</ButtonText>
<ButtonText>
Expand All @@ -100,12 +118,29 @@ const OngoingMissionButton = ({ missionName, robotId, missionTaskType }: Mission
const PausedMissionButton = ({ missionName, robotId, missionTaskType }: MissionProps) => {
const { TranslateText } = useLanguageContext()
const { updateRobotMissionState } = useMissionControlContext()
const [isDialogOpen, setIsDialogOpen] = useState(false)
const toggleStopMissionDialog = () => {
setIsDialogOpen(!isDialogOpen)
}

return (
<>
<ButtonStyle>
<ButtonText>
<StopMissionDialog missionName={missionName} robotId={robotId} missionTaskType={missionTaskType} />
<Button variant="ghost_icon" onClick={toggleStopMissionDialog}>
<Icon
name={Icons.StopButton}
style={{ color: tokens.colors.interactive.secondary__resting.rgba }}
size={40}
/>
<StopMissionDialog
missionName={missionName}
robotId={robotId}
missionTaskType={missionTaskType}
isStopMissionDialogOpen={isDialogOpen}
toggleDialog={toggleStopMissionDialog}
/>
</Button>
<Typography variant="caption">{TranslateText('Stop')}</Typography>
</ButtonText>
<ButtonText>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Button, Dialog, Typography, Icon } from '@equinor/eds-core-react'
import { Button, Dialog, Typography } from '@equinor/eds-core-react'
import styled from 'styled-components'
import { useLanguageContext } from 'components/Contexts/LanguageContext'
import { Icons } from 'utils/icons'
import { useState } from 'react'
import { tokens } from '@equinor/eds-tokens'
import { useMissionControlContext } from 'components/Contexts/MissionControlContext'
import { BackendAPICaller } from 'api/ApiCaller'
import { useInstallationContext } from 'components/Contexts/InstallationContext'
Expand Down Expand Up @@ -41,9 +39,9 @@ const StyledButton = styled(Button)`
`

interface MissionProps {
missionName: string
missionName?: string
robotId: string
missionTaskType: TaskType
missionTaskType: TaskType | undefined
}

export enum MissionStatusRequest {
Expand All @@ -52,7 +50,7 @@ export enum MissionStatusRequest {
Resume,
}

const DialogContent = ({ missionTaskType }: { missionTaskType: TaskType }) => {
const DialogContent = ({ missionTaskType }: { missionTaskType: TaskType | undefined }) => {
const { TranslateText } = useLanguageContext()
switch (missionTaskType) {
case TaskType.Localization:
Expand All @@ -77,7 +75,7 @@ const DialogContent = ({ missionTaskType }: { missionTaskType: TaskType }) => {
</Typography>
</StyledText>
)
default:
case TaskType.Inspection:
return (
<StyledText>
<Typography variant="body_long">{TranslateText('Stop button pressed warning text')}</Typography>
Expand All @@ -86,51 +84,58 @@ const DialogContent = ({ missionTaskType }: { missionTaskType: TaskType }) => {
</Typography>
</StyledText>
)
default:
return (
<StyledText>
<Typography variant="body_long">
{TranslateText('Stop button pressed with no tasktype warning text')}
</Typography>
<Typography variant="body_long">
{TranslateText('Stop button pressed with no mission confirmation text')}
</Typography>
</StyledText>
)
}
}

export const StopMissionDialog = ({ missionName, robotId, missionTaskType }: MissionProps): JSX.Element => {
export const StopMissionDialog = ({
missionName,
robotId,
missionTaskType,
isStopMissionDialogOpen,
toggleDialog,
}: MissionProps & { isStopMissionDialogOpen: boolean; toggleDialog: () => void }): JSX.Element => {
const { TranslateText } = useLanguageContext()
const [isStopMissionDialogOpen, setIsStopMissionDialogOpen] = useState<boolean>(false)
const { updateRobotMissionState } = useMissionControlContext()

return (
<>
<Button variant="ghost_icon" onClick={() => setIsStopMissionDialogOpen(true)}>
<Icon
name={Icons.StopButton}
style={{ color: tokens.colors.interactive.secondary__resting.rgba }}
size={40}
/>
</Button>

<StyledDialog open={isStopMissionDialogOpen} isDismissable>
<Dialog.Header>
<Dialog.Title>
<Typography variant="h5">
{TranslateText('Stop mission')} <strong>'{missionName}'</strong>?{' '}
</Typography>
</Dialog.Title>
</Dialog.Header>
<Dialog.CustomContent>
<DialogContent missionTaskType={missionTaskType} />
</Dialog.CustomContent>
<Dialog.Actions>
<StyledDisplayButtons>
<Button variant="outlined" color="danger" onClick={() => setIsStopMissionDialogOpen(false)}>
{TranslateText('Cancel')}
</Button>
<Button
variant="contained"
color="danger"
onClick={() => updateRobotMissionState(MissionStatusRequest.Stop, robotId)}
>
{TranslateText('Stop mission')}
</Button>
</StyledDisplayButtons>
</Dialog.Actions>
</StyledDialog>
</>
<StyledDialog open={isStopMissionDialogOpen} isDismissable>
<Dialog.Header>
<Dialog.Title>
<Typography variant="h5">
{missionName ? TranslateText('Stop mission:') : TranslateText('No mission running')}{' '}
{missionName && missionName}
</Typography>
</Dialog.Title>
</Dialog.Header>
<Dialog.CustomContent>
<DialogContent missionTaskType={missionTaskType} />
</Dialog.CustomContent>
<Dialog.Actions>
<StyledDisplayButtons>
<Button variant="outlined" color="danger" onClick={toggleDialog}>
{TranslateText('Cancel')}
</Button>
<Button
variant="contained"
color="danger"
onClick={() => updateRobotMissionState(MissionStatusRequest.Stop, robotId)}
>
{TranslateText('Stop mission')}
</Button>
</StyledDisplayButtons>
</Dialog.Actions>
</StyledDialog>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Card, Typography } from '@equinor/eds-core-react'
import { Button, Card, Icon, Typography } from '@equinor/eds-core-react'
import { Robot, RobotStatus } from 'models/Robot'
import { tokens } from '@equinor/eds-tokens'
import { RobotStatusChip } from 'components/Displays/RobotDisplays/RobotStatusIcon'
Expand All @@ -11,6 +11,10 @@ import { PressureStatusDisplay } from 'components/Displays/RobotDisplays/Pressur
import { config } from 'config'
import { RobotType } from 'models/RobotModel'
import { Mission } from 'models/Mission'
import { StopMissionDialog } from '../MissionOverview/StopDialogs'
import { useState } from 'react'
import { TaskType } from 'models/Task'
import { Icons } from 'utils/icons'

interface RobotProps {
robot: Robot
Expand Down Expand Up @@ -77,6 +81,12 @@ const LongTypography = styled(Typography)`
word-break: break-word;
}
`
const StyledButton = styled(Button)`
height: auto;
min-height: ${tokens.shape.button.minHeight};
margin-top: 10px;
width: 100%;
`

export const RobotStatusCard = ({ robot, mission }: RobotProps) => {
let navigate = useNavigate()
Expand All @@ -85,12 +95,21 @@ export const RobotStatusCard = ({ robot, mission }: RobotProps) => {
const path = `${config.FRONTEND_BASE_ROUTE}/robot/${robot.id}`
navigate(path)
}
const [isDialogOpen, setIsDialogOpen] = useState(false)
const toggleStopMissionDialog = () => {
setIsDialogOpen(!isDialogOpen)
}

const getRobotModel = (type: RobotType) => {
if (type === RobotType.TaurobInspector || type === RobotType.TaurobOperator) return 'Taurob'
return type
}

let missionTaskType = undefined
if (mission?.tasks.every((task) => task.type === TaskType.Inspection)) missionTaskType = TaskType.Inspection
if (mission?.tasks.every((task) => task.type === TaskType.ReturnHome)) missionTaskType = TaskType.ReturnHome
if (mission?.tasks.every((task) => task.type === TaskType.Localization)) missionTaskType = TaskType.Localization

return (
<HoverableStyledCard style={{ boxShadow: tokens.elevation.raised }} onClick={goToRobot}>
<RobotImage robotType={robot.model.type} height="180px" />
Expand Down Expand Up @@ -143,6 +162,27 @@ export const RobotStatusCard = ({ robot, mission }: RobotProps) => {
<></>
)}
</HorizontalContent>
<StyledButton
variant="contained"
onClick={(event) => {
event.stopPropagation()
toggleStopMissionDialog()
}}
>
<Icon
name={Icons.StopButton}
style={{ color: tokens.colors.interactive.icon_on_interactive_colors.rgba }}
size={24}
/>
{TranslateText('Stop')} {robot.name}
<StopMissionDialog
missionName={mission?.name}
robotId={robot.id}
missionTaskType={missionTaskType}
isStopMissionDialogOpen={isDialogOpen}
toggleDialog={toggleStopMissionDialog}
/>
</StyledButton>
</ButtonCard>
</HoverableStyledCard>
)
Expand Down
40 changes: 39 additions & 1 deletion frontend/src/components/Pages/RobotPage/RobotPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Typography } from '@equinor/eds-core-react'
import { Icon, Typography } from '@equinor/eds-core-react'
import { useParams } from 'react-router-dom'
import styled from 'styled-components'
import { BackButton } from 'utils/BackButton'
Expand All @@ -23,6 +23,11 @@ import { useMediaStreamContext } from 'components/Contexts/MediaStreamContext'
import { VideoStreamSection } from '../MissionPage/MissionPage'
import { useEffect, useState } from 'react'
import { VideoStreamWindow } from '../MissionPage/VideoStream/VideoStreamWindow'
import { Icons } from 'utils/icons'
import { tokens } from '@equinor/eds-tokens'
import { StopMissionDialog } from '../FrontPage/MissionOverview/StopDialogs'
import { TaskType } from 'models/Task'
import { useMissionsContext } from 'components/Contexts/MissionRunsContext'

const RobotArmMovementSection = styled.div`
display: flex;
Expand Down Expand Up @@ -66,9 +71,22 @@ export const RobotPage = () => {
const { enabledRobots } = useRobotContext()
const { mediaStreams } = useMediaStreamContext()
const [videoMediaStreams, setVideoMediaStreams] = useState<MediaStreamTrack[]>([])
const { ongoingMissions } = useMissionsContext()

const selectedRobot = enabledRobots.find((robot) => robot.id === robotId)

const [isDialogOpen, setIsDialogOpen] = useState(false)
const toggleStopMissionDialog = () => {
setIsDialogOpen(!isDialogOpen)
}

const mission = ongoingMissions.find((mission) => mission.robot.id === selectedRobot?.id)

let missionTaskType = undefined
if (mission?.tasks.every((task) => task.type === TaskType.Inspection)) missionTaskType = TaskType.Inspection
if (mission?.tasks.every((task) => task.type === TaskType.ReturnHome)) missionTaskType = TaskType.ReturnHome
if (mission?.tasks.every((task) => task.type === TaskType.Localization)) missionTaskType = TaskType.Localization

const returnRobotToHome = () => {
if (robotId) {
BackendAPICaller.returnRobotToHome(robotId).catch((e) => {
Expand Down Expand Up @@ -144,6 +162,26 @@ export const RobotPage = () => {
{selectedRobot.model.type === RobotType.TaurobInspector && <PressureTable />}
<Typography variant="h2">{TranslateText('Actions')}</Typography>

<StyledTextButton
variant="contained"
onClick={() => {
toggleStopMissionDialog()
}}
>
<Icon
name={Icons.StopButton}
style={{ color: tokens.colors.interactive.icon_on_interactive_colors.rgba }}
size={24}
/>
{TranslateText('Stop')} {selectedRobot.name}
<StopMissionDialog
missionName={mission?.name}
robotId={selectedRobot.id}
missionTaskType={missionTaskType}
isStopMissionDialogOpen={isDialogOpen}
toggleDialog={toggleStopMissionDialog}
/>
</StyledTextButton>
<StyledTextButton variant="outlined" onClick={returnRobotToHome}>
{TranslateText('Return robot to home')}
</StyledTextButton>
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/language/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"Stop button pressed warning text": "You are about to stop the entire mission. If there are no more missions in the queue, the robot will return to the start position.",
"Stop button pressed confirmation text": "Are you sure you want to stop the mission?",
"Stop mission": "Stop mission",
"Stop mission:": "Stop mission: ",
"Search for missions": "Search for missions",
"Search for a tag": "Search for a tag",
"Search for a robot name": "Search for a robot name",
Expand Down Expand Up @@ -267,5 +268,8 @@
"Failed to retrieve previous mission runs": "Failed to retrieve previous mission runs",
"Documentation": "Documentation",
"Map of {0}": "Map of {0}",
"Docked": "Docked"
"Docked": "Docked",
"Stop button pressed with no tasktype warning text": "A stop command was recieved with no ongoing tasks.",
"No mission running": "No Flotilla mission is running",
"Stop button pressed with no mission confirmation text": "Do you want to send the stop command to the robot regardless?"
}
6 changes: 5 additions & 1 deletion frontend/src/language/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"Stop button pressed warning text": "Du er i ferd med å stoppe hele oppdraget. Hvis det ikke er flere oppdrag i kø vil roboten bli sendt tilbake til startposisjonen sin.",
"Stop button pressed confirmation text": "Er du sikker på at du vil stoppe oppdraget?",
"Stop mission": "Stopp oppdraget",
"Stop mission:": "Stopp oppdrag: ",
"Search for missions": "Søk etter oppdrag",
"Search for a tag": "Søk etter tag",
"Search for a robot name": "Søk etter robotnavn",
Expand Down Expand Up @@ -267,5 +268,8 @@
"Failed to retrieve previous mission runs": "Kunne ikke hente tildigere oppdragskjøringer",
"Documentation": "Dokumentasjon",
"Map of {0}": "Kart over {0}",
"Docked": "Ladestasjon"
"Docked": "Ladestasjon",
"No mission running": "Ingen pågående Flotilla oppdrag",
"Stop button pressed with no tasktype warning text": "Et stopp signal ble mottat uten noen pågående oppdrag.",
"Stop button pressed with no mission confirmation text": "Ønsker du å sende stopp signalet til roboten likevel?"
}