diff --git a/frontend/src/components/Displays/MissionButtons/MissionRestartButton.tsx b/frontend/src/components/Displays/MissionButtons/MissionRestartButton.tsx index 92cb7e648..38492774f 100644 --- a/frontend/src/components/Displays/MissionButtons/MissionRestartButton.tsx +++ b/frontend/src/components/Displays/MissionButtons/MissionRestartButton.tsx @@ -20,6 +20,7 @@ const Centered = styled.div` ` const StyledButton = styled(Button)` background-color: none; + height: fit-content; ` interface MissionProps { diff --git a/frontend/src/components/Header/Header.tsx b/frontend/src/components/Header/Header.tsx index de3d61ad4..32e6c8fdc 100644 --- a/frontend/src/components/Header/Header.tsx +++ b/frontend/src/components/Header/Header.tsx @@ -18,6 +18,7 @@ const StyledTopBar = styled(TopBar)` @media (max-width: 600px) { grid-column-gap: 12px; } + height: fit-content; ` const StyledWrapper = styled.div` display: flex; diff --git a/frontend/src/components/Pages/FrontPage/FrontPage.tsx b/frontend/src/components/Pages/FrontPage/FrontPage.tsx index 4312ec1cb..1fba7bb79 100644 --- a/frontend/src/components/Pages/FrontPage/FrontPage.tsx +++ b/frontend/src/components/Pages/FrontPage/FrontPage.tsx @@ -6,11 +6,12 @@ import { tokens } from '@equinor/eds-tokens' import { MissionControlSection } from './MissionOverview/MissionControlSection' const StyledFrontPage = styled.div` - display: grid; - grid-template-columns: repeat(auto-fill, minmax(100%, 1fr)); + display: flex; + flex-direction: column; gap: 3rem; padding: 15px 15px; background-color: ${tokens.colors.ui.background__light.hex}; + min-height: calc(100vh - 65px); ` export const FrontPage = () => { diff --git a/frontend/src/components/Pages/MissionPage/MapPosition/MissionMapView.tsx b/frontend/src/components/Pages/MissionPage/MapPosition/MissionMapView.tsx index b32b184d6..1533cdfc9 100644 --- a/frontend/src/components/Pages/MissionPage/MapPosition/MissionMapView.tsx +++ b/frontend/src/components/Pages/MissionPage/MapPosition/MissionMapView.tsx @@ -1,9 +1,8 @@ import { Card, Typography } from '@equinor/eds-core-react' import { tokens } from '@equinor/eds-tokens' import { Mission } from 'models/Mission' -import { useCallback, useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useState } from 'react' import styled from 'styled-components' -import NoMap from 'mediaAssets/NoMap.png' import { placeRobotInMap, placeTagsInMap } from 'utils/MapMarkers' import { BackendAPICaller } from 'api/ApiCaller' import { TaskStatus } from 'models/Task' @@ -19,23 +18,25 @@ const MapCard = styled(Card)` max-width: 600px; padding: 16px; justify-items: center; + gap: 5px; ` const StyledMap = styled.canvas` object-fit: contain; max-height: 100%; max-width: 90%; - margin: auto; ` const StyledElements = styled.div` display: flex; flex-direction: columns; align-items: end; ` -const SyledContainer = styled.div` - display: flex; - max-height: 600px; - max-width: 100%; -` + +export const getMeta = async (url: string) => { + const image = new Image() + image.src = url + await image.decode() + return image +} export const MissionMapView = ({ mission }: MissionProps) => { const { enabledRobots } = useRobotContext() @@ -43,10 +44,8 @@ export const MissionMapView = ({ mission }: MissionProps) => { const [mapImage, setMapImage] = useState(document.createElement('img')) const [mapContext, setMapContext] = useState() const [currentTaskOrder, setCurrentTaskOrder] = useState(0) - const missionRobot = enabledRobots.find((robot) => robot.id === mission.robot.id) - - const imageObjectURL = useRef('') + const [displayMap, setDisplayMap] = useState(false) const updateMap = useCallback(() => { let context = mapCanvas.getContext('2d') @@ -61,13 +60,6 @@ export const MissionMapView = ({ mission }: MissionProps) => { } }, [currentTaskOrder, mapCanvas, mapImage, mission, missionRobot?.pose]) - const getMeta = async (url: string) => { - const image = new Image() - image.src = url - await image.decode() - return image - } - const findCurrentTaskOrder = useCallback( () => mission.tasks @@ -80,29 +72,31 @@ export const MissionMapView = ({ mission }: MissionProps) => { displayedMapName = displayedMapName ? displayedMapName.charAt(0).toUpperCase() + displayedMapName.slice(1) : ' ' useEffect(() => { + const processImageURL = (imageBlob: Blob | string) => { + const imageObjectURL = typeof imageBlob === 'string' ? imageBlob : URL.createObjectURL(imageBlob as Blob) + if (!imageObjectURL) return + + getMeta(imageObjectURL as string).then((img) => { + const mapCanvas = document.getElementById('missionPageMapCanvas') as HTMLCanvasElement + if (!mapCanvas) return + mapCanvas.width = img.width + mapCanvas.height = img.height + let context = mapCanvas?.getContext('2d') + if (context) { + setMapContext(context) + context.drawImage(img, 0, 0) + } + setMapCanvas(mapCanvas) + setMapImage(img) + }) + } + BackendAPICaller.getMap(mission.installationCode!, mission.map?.mapName!) .then((imageBlob) => { - imageObjectURL.current = URL.createObjectURL(imageBlob) - }) - .catch(() => { - imageObjectURL.current = NoMap - }) - .then(() => { - getMeta(imageObjectURL.current).then((img) => { - const mapCanvas = document.getElementById('mapCanvas') as HTMLCanvasElement - if (mapCanvas) { - mapCanvas.width = img.width - mapCanvas.height = img.height - let context = mapCanvas?.getContext('2d') - if (context) { - setMapContext(context) - context.drawImage(img, 0, 0) - } - setMapCanvas(mapCanvas) - } - setMapImage(img) - }) + processImageURL(imageBlob) + setDisplayMap(true) }) + .catch(() => {}) }, [mission.installationCode, mission.id, mission.map?.mapName]) useEffect(() => { @@ -129,14 +123,16 @@ export const MissionMapView = ({ mission }: MissionProps) => { }, [updateMap, mapContext]) return ( - - {displayedMapName} - - - - {imageObjectURL.current !== NoMap && mapContext && } - - - + <> + {displayMap && ( + + {displayedMapName} + + + {mapContext && } + + + )} + ) } diff --git a/frontend/src/components/Pages/MissionPage/MissionHeader/MissionHeader.tsx b/frontend/src/components/Pages/MissionPage/MissionHeader/MissionHeader.tsx index 4a2c93925..433b5dbc5 100644 --- a/frontend/src/components/Pages/MissionPage/MissionHeader/MissionHeader.tsx +++ b/frontend/src/components/Pages/MissionPage/MissionHeader/MissionHeader.tsx @@ -17,8 +17,8 @@ const HeaderSection = styled(Card)` top: 60px; position: sticky; z-index: 1; - background-color: ${tokens.colors.ui.background__light.hex}; box-shadow: none; + background-color: ${tokens.colors.ui.background__light.hex}; ` const TitleSection = styled.div` display: flex; @@ -28,17 +28,15 @@ const TitleSection = styled.div` const InfoSection = styled.div` display: flex; flex-wrap: wrap; - gap: 8px; - max-width: 950px; -` -const StyledCard = styled(Card)` - display: flex; - flex: 1 0 0; - padding: 8px 16px; - flex-direction: row; - background: ${tokens.colors.ui.background__default.hex}; - gap: 24px; - align-items: stretch; + gap: 32px; + width: fit-content; + @media (max-width: 600px) { + display: grid; + grid-template-columns: repeat(3, calc(75vw / 3)); + gap: 32px; + width: fit-content; + align-items: end; + } ` const StyledTitleText = styled.div` display: grid; @@ -51,12 +49,25 @@ const StyledTypography = styled(Typography)` font-style: normal; font-weight: 400; line-height: 40px; /* 125% */ - @media (max-width: 500px) { font-size: 24px; } ` +const StyledMissionHeader = styled(Card)` + display: flex; + padding: 24px 10px 10px 10px; + flex-direction: column; + align-items: flex-start; + gap: 24px; + flex: 1 0 0; + align-self: stretch; + border-radius: 6px; + border: 1px solid ${tokens.colors.ui.background__medium.rgba}; + background: ${tokens.colors.ui.background__default.rgba}; + max-width: fit-content; +` + const HeaderText = (title: string, text: string) => { return ( @@ -186,23 +197,18 @@ export const MissionHeader = ({ mission }: { mission: Mission }) => { - - + +
{HeaderText(translatedStatus, '')}
+ {HeaderText(translatedArea, `${mission.area?.areaName}`)} {HeaderText(translatedTasks, `${numberOfCompletedTasks + '/' + mission.tasks.length}`)} -
- {HeaderText(translatedStartDate, `${startDate}`)} {HeaderText(translatedStartTime, `${startTime}`)} - - {HeaderText(translatedUsedTime, `${usedTime}`)} {!isMissionCompleted && HeaderText(translatedEstimatedTimeRemaining, `${remainingTime}`)} - - {HeaderText(translatedRobot, `${mission.robot.name}`)} {!isMissionCompleted && HeaderText(translatedBatteryLevel, batteryValue)} {!isMissionCompleted && @@ -212,8 +218,8 @@ export const MissionHeader = ({ mission }: { mission: Mission }) => { translatedPressureLevel, `${Math.round(mission.robot.pressureLevel * barToMillibar)}mBar` )} - -
+ + ) } diff --git a/frontend/src/components/Pages/MissionPage/MissionPage.tsx b/frontend/src/components/Pages/MissionPage/MissionPage.tsx index 89cfb67bb..708703da3 100644 --- a/frontend/src/components/Pages/MissionPage/MissionPage.tsx +++ b/frontend/src/components/Pages/MissionPage/MissionPage.tsx @@ -19,18 +19,37 @@ import { tokens } from '@equinor/eds-tokens' import { StyledPage } from 'components/Styles/StyledComponents' import { InspectionDialogView, InspectionsViewSection } from '../InspectionReportPage.tsx/InspectionView' import { useInspectionsContext } from 'components/Contexts/InpectionsContext' +import { Typography } from '@equinor/eds-core-react' const StyledMissionPage = styled(StyledPage)` background-color: ${tokens.colors.ui.background__light.hex}; ` const TaskAndMapSection = styled.div` display: flex; + min-width: 50%; + max-width: fit-content; + min-height: 60%; + padding: 24px; + @media (max-width: 600px) { + padding: 6px 8px 8px 6px; + } + flex-direction: column; + justify-content: center; align-items: flex-start; + gap: 8px; + align-self: stretch; + border-radius: 6px; + border: 1px solid ${tokens.colors.ui.background__medium.rgba}; + background: ${tokens.colors.ui.background__default.rgba}; +` + +const StyledTableAndMap = styled.div` + display: flex; flex-wrap: wrap; - gap: 8rem; - padding-top: 16px; - padding-bottom: 16px; + align-items: top; + gap: 24px; ` + export const VideoStreamSection = styled.div` display: grid; gap: 1rem; @@ -104,8 +123,11 @@ export const MissionPage = () => { <> - - + {TranslateText('Tasks')} + + + + {videoMediaStreams && videoMediaStreams.length > 0 && ( diff --git a/frontend/src/components/Pages/MissionPage/TaskOverview/TaskTable.tsx b/frontend/src/components/Pages/MissionPage/TaskOverview/TaskTable.tsx index f2106a3c4..3225ec2f3 100644 --- a/frontend/src/components/Pages/MissionPage/TaskOverview/TaskTable.tsx +++ b/frontend/src/components/Pages/MissionPage/TaskOverview/TaskTable.tsx @@ -5,7 +5,6 @@ import { useLanguageContext } from 'components/Contexts/LanguageContext' import { Task, TaskStatus } from 'models/Task' import { tokens } from '@equinor/eds-tokens' import { getColorsFromTaskStatus } from 'utils/MarkerStyles' -import { StyledTableBody, StyledTableCaptionGray, StyledTableCell } from 'components/Styles/StyledComponents' import { InspectionType } from 'models/Inspection' import { useInspectionsContext } from 'components/Contexts/InpectionsContext' @@ -35,23 +34,18 @@ export const TaskTable = ({ tasks }: TaskTableProps) => { const { TranslateText } = useLanguageContext() return ( - <> - - - {TranslateText('Tasks')} - - - - # - {TranslateText('Tag-ID')} - {TranslateText('Description')} - {TranslateText('Inspection Types')} - {TranslateText('Status')} - - - {tasks && } - - + + + + # + {TranslateText('Tag-ID')} + {TranslateText('Description')} + {TranslateText('Inspection Types')} + {TranslateText('Status')} + + + {tasks && } + ) } diff --git a/frontend/src/components/Styles/StyledComponents.tsx b/frontend/src/components/Styles/StyledComponents.tsx index ce9ef4511..7db11d354 100644 --- a/frontend/src/components/Styles/StyledComponents.tsx +++ b/frontend/src/components/Styles/StyledComponents.tsx @@ -52,6 +52,3 @@ export const StyledTableBody = styled(Table.Body)` export const StyledTableCaption = styled(Table.Caption)` background-color: ${tokens.colors.ui.background__default.hex}; ` -export const StyledTableCaptionGray = styled(Table.Caption)` - background-color: ${tokens.colors.ui.background__light.hex}; -` diff --git a/frontend/src/utils/DeckMapView.tsx b/frontend/src/utils/DeckMapView.tsx index 71a54cd12..2ec75b4dc 100644 --- a/frontend/src/utils/DeckMapView.tsx +++ b/frontend/src/utils/DeckMapView.tsx @@ -9,6 +9,7 @@ import { Pose } from 'models/Pose' import { MapCompass } from 'utils/MapCompass' import { Deck } from 'models/Deck' import { useLanguageContext } from 'components/Contexts/LanguageContext' +import { getMeta } from 'components/Pages/MissionPage/MapPosition/MissionMapView' interface DeckProps { deck: Deck @@ -62,13 +63,6 @@ export const DeckMapView = ({ deck, markedRobotPosition }: DeckProps) => { } }, [mapCanvas, mapImage, mapMetadata, markedRobotPosition]) - const getMeta = async (url: string) => { - const image = new Image() - image.src = url - await image.decode() - return image - } - let mapName = mapMetadata?.mapName.split('.')[0].replace(/[^0-9a-z-A-Z ]/g, ' ') mapName = mapName ? mapName.charAt(0).toUpperCase() + mapName.slice(1) : ' ' @@ -137,9 +131,11 @@ export const DeckMapView = ({ deck, markedRobotPosition }: DeckProps) => { {mapMetadata && } - - {TranslateText('Map of {0}', [mapName])} - + {mapMetadata !== undefined && ( + + {TranslateText('Map of {0}', [mapName])} + + )} )}