Skip to content

Commit

Permalink
Add feedback when localizing the robot
Browse files Browse the repository at this point in the history
  • Loading branch information
mrica-equinor committed Jul 26, 2023
1 parent 823c202 commit cd8f4e9
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 27 deletions.
11 changes: 11 additions & 0 deletions frontend/src/components/Contexts/LanguageContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ interface ILanguageContext {
language: string
textDictionary: { [text: string]: string }
switchLanguage: (newLanguage: string) => void
translate: (str: string) => string
}

interface Props {
Expand All @@ -15,6 +16,7 @@ const defaultLanguageInterface = {
language: defaultLanguage,
textDictionary: allLanguageDictionaries[defaultLanguage],
switchLanguage: (newLanguage: string) => {},
translate: (str: string) => '',
}

export const LanguageContext = createContext<ILanguageContext>(defaultLanguageInterface)
Expand All @@ -31,12 +33,21 @@ export const LanguageProvider: FC<Props> = ({ children }) => {
window.localStorage.setItem('flotilla-language', newLanguage)
}

const translate = (str: string): string => {
if (textDictionary[str]) {
return textDictionary[str]
}
console.warn(`Translation issue: "${str}" has no translation to language "${language}"`)
return str
}

return (
<LanguageContext.Provider
value={{
language,
textDictionary,
switchLanguage,
translate,
}}
>
{children}
Expand Down
116 changes: 92 additions & 24 deletions frontend/src/components/Pages/RobotPage/LocalizationDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Autocomplete, AutocompleteChanges, Button, Card, Dialog, Typography, Icon } from '@equinor/eds-core-react'
import styled from 'styled-components'
import { TranslateText } from 'components/Contexts/LanguageContext'
import { useLanguageContext } from 'components/Contexts/LanguageContext'
import { Icons } from 'utils/icons'
import { useState, useEffect } from 'react'
import { BackendAPICaller } from 'api/ApiCaller'
Expand All @@ -9,6 +9,8 @@ import { Robot } from 'models/Robot'
import { AssetDeckMapView } from './AssetDeckMapView'
import { Pose } from 'models/Pose'
import { Orientation } from 'models/Orientation'
import { Mission, MissionStatus } from 'models/Mission'
import { tokens } from '@equinor/eds-tokens'

const StyledDialog = styled(Card)`
display: flex;
Expand All @@ -23,8 +25,9 @@ const StyledAutoComplete = styled.div`
justify-content: space-evenly;
`

const StyledLocalizationButton = styled.div`
const StyledLocalization = styled.div`
display: flex;
gap: 8px;
`

const StyledButtons = styled.div`
Expand All @@ -33,22 +36,36 @@ const StyledButtons = styled.div`
justify-content: flex-end;
`

const StyledCard = styled(Card)`
display: flex;
justify-content: center;
align-items: center;
max-width: 300px;
height: 36px;s
`

interface RobotProps {
robot: Robot
}

export const LocalizationDialog = ({ robot }: RobotProps): JSX.Element => {
const [isLocalizationDialogOpen, setIsLocalizationDialogOpen] = useState<boolean>(false)
const [missionLocalizationStatus, setMissionLocalizationInfo] = useState<string>()
const [selectedAssetDeck, setSelectedAssetDeck] = useState<AssetDeck>()
const [assetDecks, setAssetDecks] = useState<AssetDeck[]>()
const [localisationPose, setLocalizationPose] = useState<Pose>()
const [localizationPose, setLocalizationPose] = useState<Pose>()
const [selectedDirection, setSelectedDirecion] = useState<Orientation>()
const [localizing, setLocalising] = useState<Boolean>(false)
const { translate } = useLanguageContext()

const colorGreen = '#A1DAA0'
const colorGreenToken = tokens.colors.text.static_icons__default.hex

const directionMap: Map<string, Orientation> = new Map([
[TranslateText('North'), { x: 0, y: 0, z: 0.7071, w: 0.7071 }],
[TranslateText('East'), { x: 0, y: 0, z: 0, w: 1 }],
[TranslateText('South'), { x: 0, y: 0, z: -0.7071, w: 0.7071 }],
[TranslateText('West'), { x: 0, y: 0, z: 1, w: 0 }],
[translate('North'), { x: 0, y: 0, z: 0.7071, w: 0.7071 }],
[translate('East'), { x: 0, y: 0, z: 0, w: 1 }],
[translate('South'), { x: 0, y: 0, z: -0.7071, w: 0.7071 }],
[translate('West'), { x: 0, y: 0, z: 1, w: 0 }],
])

useEffect(() => {
Expand All @@ -57,6 +74,26 @@ export const LocalizationDialog = ({ robot }: RobotProps): JSX.Element => {
})
}, [])

useEffect(() => {
if (selectedAssetDeck && localizationPose && localizing) {
BackendAPICaller.postLocalizationMission(localizationPose, robot.id, selectedAssetDeck.id)
.then((result: unknown) => result as Mission)
.then(async (mission: Mission) => {
BackendAPICaller.getMissionById(mission.id)
while (mission.status == MissionStatus.Ongoing || mission.status == MissionStatus.Pending) {
mission = await BackendAPICaller.getMissionById(mission.id)
}
setLocalising(false)
return mission
})
.then((mission: Mission) => setMissionLocalizationInfo(mission.status))
.catch((e) => {
console.error(e)
})
onLocalizationDialogClose()
}
}, [localizing])

const getAssetDeckNames = (assetDecks: AssetDeck[]): Map<string, AssetDeck> => {
var assetDeckNameMap = new Map<string, AssetDeck>()
assetDecks.forEach((assetDeck: AssetDeck) => {
Expand All @@ -79,7 +116,7 @@ export const LocalizationDialog = ({ robot }: RobotProps): JSX.Element => {
const onSelectedDirection = (changes: AutocompleteChanges<string>) => {
const selectedDirection = directionMap.get(changes.selectedItems[0])
setSelectedDirecion(selectedDirection)
let newPose = localisationPose
let newPose = localizationPose
if (newPose && selectedDirection) {
newPose.orientation = selectedDirection
setLocalizationPose(newPose)
Expand All @@ -95,47 +132,78 @@ export const LocalizationDialog = ({ robot }: RobotProps): JSX.Element => {
setSelectedAssetDeck(undefined)
}

const onClickLocalize = () => {
if (selectedAssetDeck && localisationPose) {
BackendAPICaller.postLocalizationMission(localisationPose, robot.id, selectedAssetDeck.id)
}
onLocalizationDialogClose()
const onClickLocalize = async () => {
setMissionLocalizationInfo(undefined)
setLocalising(true)
}
const assetDeckNames = assetDecks ? Array.from(getAssetDeckNames(assetDecks).keys()).sort() : []

const assetDeckNames = assetDecks ? Array.from(getAssetDeckNames(assetDecks).keys()).sort() : []
return (
<>
<StyledLocalizationButton>
<StyledLocalization>
<Button
onClick={() => {
onClickLocalizeRobot()
}}
>
<>
<Icon name={Icons.PinDrop} size={16} />
{TranslateText('Localize robot')}
{translate('Localize robot')}
</>
</Button>
</StyledLocalizationButton>
{(localizing || missionLocalizationStatus) && (
<>
{!missionLocalizationStatus && (
<StyledCard variant="info">
<StyledCard.Header>
<Typography variant="body_short">{translate('Localizing') + '...'}</Typography>
</StyledCard.Header>
</StyledCard>
)}
{missionLocalizationStatus == MissionStatus.Successful && (
<StyledCard style={{ background: colorGreen, color: colorGreenToken }}>
<StyledCard.Header>
<Typography variant="body_short">
{translate('Localization') +
' ' +
translate(missionLocalizationStatus).toLocaleLowerCase()}
</Typography>
</StyledCard.Header>
</StyledCard>
)}
{missionLocalizationStatus && missionLocalizationStatus !== MissionStatus.Successful && (
<StyledCard variant="danger">
<StyledCard.Header>
<Typography variant="body_short">
{translate('Localization') +
' ' +
translate(missionLocalizationStatus).toLocaleLowerCase()}
</Typography>
</StyledCard.Header>
</StyledCard>
)}
</>
)}
</StyledLocalization>
<Dialog open={isLocalizationDialogOpen} isDismissable>
<StyledDialog>
<Typography variant="h2">{TranslateText('Localize robot')}</Typography>
<Typography variant="h2">{translate('Localize robot')}</Typography>
<StyledAutoComplete>
<Autocomplete
options={assetDeckNames}
label={TranslateText('Select deck')}
label={translate('Select deck')}
onOptionsChange={onSelectedDeck}
/>
<Autocomplete
options={Array.from(directionMap.keys())}
label={TranslateText('Select direction')}
label={translate('Select direction')}
onOptionsChange={onSelectedDirection}
/>
</StyledAutoComplete>
{selectedAssetDeck && localisationPose && (
{selectedAssetDeck && localizationPose && (
<AssetDeckMapView
assetDeck={selectedAssetDeck}
localizationPose={localisationPose}
localizationPose={localizationPose}
setLocalizationPose={setLocalizationPose}
/>
)}
Expand All @@ -148,11 +216,11 @@ export const LocalizationDialog = ({ robot }: RobotProps): JSX.Element => {
color="secondary"
>
{' '}
{TranslateText('Cancel')}{' '}
{translate('Cancel')}{' '}
</Button>
<Button onClick={onClickLocalize} disabled={!selectedAssetDeck}>
{' '}
{TranslateText('Localize')}{' '}
{translate('Localize')}{' '}
</Button>
</StyledButtons>
</StyledDialog>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/language/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,6 @@
"Select max end time": "Select max end time",
"selected": "selected",
"This button is disabled because the robot is not available. Check that the robot is on, and are not doing any other activities.": "This button is disabled because the robot is not available. Check that the robot is on, and are not doing any other activities.",
"Close": "Close"
"Close": "Close",
"Localizing": "Localizing"
}
2 changes: 1 addition & 1 deletion frontend/src/language/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import no from './no.json'

export const defaultLanguage = 'en'
export const languageOptions: { [key: string]: string } = { en: 'English', no: 'Norsk' }
export const allLanguageDictionaries: { [key: string]: {} } = { en, no }
export const allLanguageDictionaries: { [key: string]: Record<string, string> } = { en, no }

export const LanguageShort = (languageLong: string) => {
const langKey = (Object.keys(languageOptions) as (keyof typeof languageOptions)[]).find((key) => {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/language/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,6 @@
"Select max end time": "Velg maks sluttid",
"selected": "valgte",
"This button is disabled because the robot is not available. Check that the robot is on, and are not doing any other activities.": "Denne knappen er deaktivert fordi roboten ikke er tilgjengelig. Sjekk at roboten er på og ikke gjør noen andre aktiviteter.",
"Close": "Steng"
"Close": "Steng",
"Localizing": "Lokaliserer"
}

0 comments on commit cd8f4e9

Please sign in to comment.