From 26d7bcf253cc7a7096bcdde716b555789f02db65 Mon Sep 17 00:00:00 2001 From: Aaron Chong Date: Tue, 26 Nov 2024 12:15:09 +0800 Subject: [PATCH] door-summary, tests, clean up unused opmode Signed-off-by: Aaron Chong --- .../beacons/beacon-table-datagrid.tsx | 4 +- .../components/doors/door-card.stories.tsx | 35 --------- .../src/components/doors/door-card.tsx | 73 ------------------- .../src/components/doors/door-controls.tsx | 25 ------- .../components/doors/door-summary.test.tsx | 66 +++++++++++++++++ .../src/components/doors/door-summary.tsx | 27 +++---- .../src/components/doors/door-utils.ts | 2 +- .../components/doors/{index.tsx => index.ts} | 1 - .../components/lifts/lift-table-datagrid.tsx | 4 +- .../src/components/map/index.tsx | 2 +- .../src/components/robots/robots-table.tsx | 2 +- .../src/components/workcells/utils.ts | 2 +- .../workcells/workcell-table.test.tsx | 2 +- 13 files changed, 87 insertions(+), 158 deletions(-) delete mode 100644 packages/rmf-dashboard-framework/src/components/doors/door-card.stories.tsx delete mode 100644 packages/rmf-dashboard-framework/src/components/doors/door-card.tsx delete mode 100644 packages/rmf-dashboard-framework/src/components/doors/door-controls.tsx create mode 100644 packages/rmf-dashboard-framework/src/components/doors/door-summary.test.tsx rename packages/rmf-dashboard-framework/src/components/doors/{index.tsx => index.ts} (68%) diff --git a/packages/rmf-dashboard-framework/src/components/beacons/beacon-table-datagrid.tsx b/packages/rmf-dashboard-framework/src/components/beacons/beacon-table-datagrid.tsx index 8af6b251e..9e5bdf7c0 100644 --- a/packages/rmf-dashboard-framework/src/components/beacons/beacon-table-datagrid.tsx +++ b/packages/rmf-dashboard-framework/src/components/beacons/beacon-table-datagrid.tsx @@ -90,7 +90,7 @@ export function BeaconDataGridTable({ beacons }: BeaconDataGridTableProps): JSX. headerName: 'Level', width: 150, editable: false, - valueGetter: (params: GridValueGetterParams) => params.row.level ?? 'N/A', + valueGetter: (params: GridValueGetterParams) => params.row.level ?? 'n/a', flex: 1, filterable: true, }, @@ -99,7 +99,7 @@ export function BeaconDataGridTable({ beacons }: BeaconDataGridTableProps): JSX. headerName: 'Type', width: 150, editable: false, - valueGetter: (params: GridValueGetterParams) => params.row.category ?? 'N/A', + valueGetter: (params: GridValueGetterParams) => params.row.category ?? 'n/a', flex: 1, filterable: true, }, diff --git a/packages/rmf-dashboard-framework/src/components/doors/door-card.stories.tsx b/packages/rmf-dashboard-framework/src/components/doors/door-card.stories.tsx deleted file mode 100644 index de399883d..000000000 --- a/packages/rmf-dashboard-framework/src/components/doors/door-card.stories.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { CardActions } from '@mui/material'; -import { Meta, StoryObj } from '@storybook/react'; -import { Door } from 'rmf-models/ros/rmf_building_map_msgs/msg'; -import { DoorMode } from 'rmf-models/ros/rmf_door_msgs/msg'; - -import { DoorCard } from './door-card'; -import { DoorControls } from './door-controls'; - -export default { - title: 'Door Card', - component: DoorCard, -} satisfies Meta; - -type Story = StoryObj; - -export const Default: Story = { - args: { - name: 'main_door', - level: 'L1', - mode: DoorMode.MODE_OPEN, - type: Door.DOOR_TYPE_SINGLE_SWING, - }, - render: (args) => , -}; - -export const WithControls: Story = { - args: Default.args, - render: (args) => ( - - - - - - ), -}; diff --git a/packages/rmf-dashboard-framework/src/components/doors/door-card.tsx b/packages/rmf-dashboard-framework/src/components/doors/door-card.tsx deleted file mode 100644 index 1c4a91344..000000000 --- a/packages/rmf-dashboard-framework/src/components/doors/door-card.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Card, CardContent, CardProps, Grid, SxProps, Typography, useTheme } from '@mui/material'; -import React from 'react'; -import { DoorMode } from 'rmf-models/ros/rmf_door_msgs/msg'; - -import { doorModeToString, doorTypeToString } from './door-utils'; - -export interface DoorCardProps extends CardProps { - name: string; - level: string; - mode: number; - type: number; -} - -export function DoorCard({ - name, - level, - mode, - type, - children, - ...cardProps -}: DoorCardProps): JSX.Element { - const theme = useTheme(); - const labelStyle = React.useMemo(() => { - switch (mode) { - case DoorMode.MODE_OPEN: - return { - backgroundColor: theme.palette.success.main, - color: theme.palette.success.contrastText, - }; - case DoorMode.MODE_CLOSED: - return { - backgroundColor: theme.palette.error.main, - color: theme.palette.error.contrastText, - }; - case DoorMode.MODE_MOVING: - return { - backgroundColor: theme.palette.warning.main, - color: theme.palette.warning.contrastText, - }; - default: - return { - backgroundColor: theme.palette.action.disabledBackground, - color: theme.palette.action.disabled, - }; - } - }, [theme, mode]); - - return ( - - - - {name} - - - - - {level} - - - - - {doorModeToString(mode)} - - - - - {doorTypeToString(type)} - - - {children} - - ); -} diff --git a/packages/rmf-dashboard-framework/src/components/doors/door-controls.tsx b/packages/rmf-dashboard-framework/src/components/doors/door-controls.tsx deleted file mode 100644 index 488b9f967..000000000 --- a/packages/rmf-dashboard-framework/src/components/doors/door-controls.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Button, ButtonGroup } from '@mui/material'; -import React from 'react'; - -export interface DoorControlsProps { - doorName?: string; - onOpenClick?(event: React.MouseEvent): void; - onCloseClick?(event: React.MouseEvent): void; -} - -export function DoorControls({ - doorName, - onOpenClick, - onCloseClick, -}: DoorControlsProps): JSX.Element { - return ( - - - - - ); -} diff --git a/packages/rmf-dashboard-framework/src/components/doors/door-summary.test.tsx b/packages/rmf-dashboard-framework/src/components/doors/door-summary.test.tsx new file mode 100644 index 000000000..910cfcf35 --- /dev/null +++ b/packages/rmf-dashboard-framework/src/components/doors/door-summary.test.tsx @@ -0,0 +1,66 @@ +import { waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { DoorState } from 'api-client'; +import React, { act } from 'react'; +import { Door as RmfDoor } from 'rmf-models/ros/rmf_building_map_msgs/msg'; +import { DoorMode as RmfDoorMode } from 'rmf-models/ros/rmf_door_msgs/msg'; +import { describe, expect, it, vi } from 'vitest'; + +import { RmfApiProvider } from '../../hooks'; +import { MockRmfApi, render, TestProviders } from '../../utils/test-utils.test'; +import { DoorSummary } from './door-summary'; +import { makeDoor } from './test-utils.test'; + +describe('DoorSummary', () => { + const mockDoor: RmfDoor = makeDoor({ name: 'test_door' }); + + const rmfApi = new MockRmfApi(); + const Base = (props: React.PropsWithChildren<{}>) => { + return ( + + {props.children} + + ); + }; + + it('renders door summary correctly', async () => { + const onCloseMock = vi.fn(); + const root = render( + + + , + ); + + // Create the subject for the door + const doorStateObs = rmfApi.getDoorStateObs('test_door'); + let emittedDoorState: DoorState | undefined; + doorStateObs.subscribe((doorState) => { + emittedDoorState = doorState; + }); + + const mockDoorState: DoorState = { + door_time: { sec: 0, nanosec: 0 }, + door_name: 'test_door', + current_mode: { value: RmfDoorMode.MODE_OPEN }, + }; + act(() => { + rmfApi.doorStateObsStore['test_door'].next(mockDoorState); + }); + + expect(emittedDoorState).toEqual(mockDoorState); + expect(emittedDoorState?.current_mode.value).toEqual(RmfDoorMode.MODE_OPEN); + + expect(root.getByText('Name')).toBeTruthy(); + expect(root.getByText('Current Floor')).toBeTruthy(); + expect(root.getByText('Type')).toBeTruthy(); + expect(root.getByText('State')).toBeTruthy(); + + expect(root.getByText('test_door')).toBeTruthy(); + expect(root.getByText('L1')).toBeTruthy(); + expect(root.getByText('Single Swing')).toBeTruthy(); + expect(root.getByText('OPEN')).toBeTruthy(); + + userEvent.keyboard('{Escape}'); + await waitFor(() => expect(onCloseMock).toHaveBeenCalledTimes(1)); + }); +}); diff --git a/packages/rmf-dashboard-framework/src/components/doors/door-summary.tsx b/packages/rmf-dashboard-framework/src/components/doors/door-summary.tsx index f50e7a231..2adde3b88 100644 --- a/packages/rmf-dashboard-framework/src/components/doors/door-summary.tsx +++ b/packages/rmf-dashboard-framework/src/components/doors/door-summary.tsx @@ -1,26 +1,25 @@ import { Dialog, DialogContent, DialogTitle, Divider, TextField, useTheme } from '@mui/material'; -import { Level } from 'api-client'; import React from 'react'; import { Door as DoorModel } from 'rmf-models/ros/rmf_building_map_msgs/msg'; import { useRmfApi } from '../../hooks'; import { getApiErrorMessage } from '../../utils/api'; -import { doorModeToOpModeString, DoorTableData } from './door-table-datagrid'; +import { DoorTableData } from './door-table-datagrid'; import { doorModeToString, doorTypeToString } from './door-utils'; interface DoorSummaryProps { onClose: () => void; door: DoorModel; - level: Level; + doorLevelName: string; } -export const DoorSummary = ({ onClose, door, level }: DoorSummaryProps): JSX.Element => { +export const DoorSummary = ({ onClose, door, doorLevelName }: DoorSummaryProps): JSX.Element => { const rmfApi = useRmfApi(); const [doorData, setDoorData] = React.useState({ index: 0, - doorName: '', - levelName: '', - doorType: 0, + doorName: door.name, + levelName: doorLevelName, + doorType: door.door_type, doorState: undefined, }); @@ -31,7 +30,7 @@ export const DoorSummary = ({ onClose, door, level }: DoorSummaryProps): JSX.Ele setDoorData({ index: 0, doorName: door.name, - levelName: level.name, + levelName: doorLevelName, doorType: door.door_type, doorState: doorState, }); @@ -43,7 +42,7 @@ export const DoorSummary = ({ onClose, door, level }: DoorSummaryProps): JSX.Ele }; fetchDataForDoor(); - }, [rmfApi, level, door]); + }, [rmfApi, doorLevelName, door]); const [isOpen, setIsOpen] = React.useState(true); @@ -70,7 +69,7 @@ export const DoorSummary = ({ onClose, door, level }: DoorSummaryProps): JSX.Ele {Object.entries(doorData).map(([key, value]) => { if (key === 'index') { - return <>; + return
; } let displayValue = value; let displayLabel = key; @@ -78,10 +77,6 @@ export const DoorSummary = ({ onClose, door, level }: DoorSummaryProps): JSX.Ele case 'doorName': displayLabel = 'Name'; break; - case 'opMode': - displayValue = doorModeToOpModeString(value.current_mode); - displayLabel = 'Op. Mode'; - break; case 'levelName': displayLabel = 'Current Floor'; break; @@ -90,7 +85,9 @@ export const DoorSummary = ({ onClose, door, level }: DoorSummaryProps): JSX.Ele displayLabel = 'Type'; break; case 'doorState': - displayValue = value ? doorModeToString(value.current_mode.value) : -1; + displayValue = value + ? doorModeToString(value.current_mode.value) + : doorModeToString(undefined); displayLabel = 'State'; break; default: diff --git a/packages/rmf-dashboard-framework/src/components/doors/door-utils.ts b/packages/rmf-dashboard-framework/src/components/doors/door-utils.ts index 5f85a366a..7a0ecc544 100644 --- a/packages/rmf-dashboard-framework/src/components/doors/door-utils.ts +++ b/packages/rmf-dashboard-framework/src/components/doors/door-utils.ts @@ -28,7 +28,7 @@ export interface DoorData { export function doorModeToString(doorMode?: number): string { if (doorMode === undefined) { - return 'N/A'; + return 'n/a'; } switch (doorMode) { case RmfDoorMode.MODE_OPEN: diff --git a/packages/rmf-dashboard-framework/src/components/doors/index.tsx b/packages/rmf-dashboard-framework/src/components/doors/index.ts similarity index 68% rename from packages/rmf-dashboard-framework/src/components/doors/index.tsx rename to packages/rmf-dashboard-framework/src/components/doors/index.ts index 9a56e4a6b..732195a65 100644 --- a/packages/rmf-dashboard-framework/src/components/doors/index.tsx +++ b/packages/rmf-dashboard-framework/src/components/doors/index.ts @@ -1,3 +1,2 @@ -export * from './door-card'; export * from './door-summary'; export * from './doors-table'; diff --git a/packages/rmf-dashboard-framework/src/components/lifts/lift-table-datagrid.tsx b/packages/rmf-dashboard-framework/src/components/lifts/lift-table-datagrid.tsx index 496900292..8d035cf2b 100644 --- a/packages/rmf-dashboard-framework/src/components/lifts/lift-table-datagrid.tsx +++ b/packages/rmf-dashboard-framework/src/components/lifts/lift-table-datagrid.tsx @@ -200,7 +200,7 @@ export function LiftDataGridTable({ lifts, onLiftClick }: LiftDataGridTableProps width: 150, editable: false, valueGetter: (params: GridValueGetterParams) => - params.row.currentFloor ? params.row.currentFloor : 'N/A', + params.row.currentFloor ? params.row.currentFloor : 'n/a', flex: 1, filterable: true, }, @@ -210,7 +210,7 @@ export function LiftDataGridTable({ lifts, onLiftClick }: LiftDataGridTableProps width: 150, editable: false, valueGetter: (params: GridValueGetterParams) => - params.row.destinationFloor ? params.row.destinationFloor : 'N/A', + params.row.destinationFloor ? params.row.destinationFloor : 'n/a', flex: 1, filterable: true, }, diff --git a/packages/rmf-dashboard-framework/src/components/map/index.tsx b/packages/rmf-dashboard-framework/src/components/map/index.tsx index 730892a06..e31e390a3 100644 --- a/packages/rmf-dashboard-framework/src/components/map/index.tsx +++ b/packages/rmf-dashboard-framework/src/components/map/index.tsx @@ -695,7 +695,7 @@ export const Map = styled((props: MapProps) => { setOpenDoorSummary(false)} door={selectedDoor} - level={currentLevel} + doorLevelName={currentLevel.name} /> )} diff --git a/packages/rmf-dashboard-framework/src/components/robots/robots-table.tsx b/packages/rmf-dashboard-framework/src/components/robots/robots-table.tsx index 29598ed6c..4e5699f45 100644 --- a/packages/rmf-dashboard-framework/src/components/robots/robots-table.tsx +++ b/packages/rmf-dashboard-framework/src/components/robots/robots-table.tsx @@ -59,7 +59,7 @@ export const RobotsTable = () => { status: robot.status || undefined, estFinishTime: estFinishTime || undefined, lastUpdateTime: robot.unix_millis_time ? robot.unix_millis_time : undefined, - level: robot.location?.map || 'N/A', + level: robot.location?.map || 'n/a', commission: robot.commission || undefined, }; }) diff --git a/packages/rmf-dashboard-framework/src/components/workcells/utils.ts b/packages/rmf-dashboard-framework/src/components/workcells/utils.ts index 1cc110722..6ffec127d 100644 --- a/packages/rmf-dashboard-framework/src/components/workcells/utils.ts +++ b/packages/rmf-dashboard-framework/src/components/workcells/utils.ts @@ -9,6 +9,6 @@ export function dispenserModeToString(mode: number): string { case RmfDispenserState.OFFLINE: return 'OFFLINE'; default: - return 'N/A'; + return 'n/a'; } } diff --git a/packages/rmf-dashboard-framework/src/components/workcells/workcell-table.test.tsx b/packages/rmf-dashboard-framework/src/components/workcells/workcell-table.test.tsx index b52667d32..900d333f1 100644 --- a/packages/rmf-dashboard-framework/src/components/workcells/workcell-table.test.tsx +++ b/packages/rmf-dashboard-framework/src/components/workcells/workcell-table.test.tsx @@ -28,6 +28,6 @@ describe('Workcell table', () => { expect(root.getByLabelText('test3')).toBeTruthy(); // check if state unknown dispenser state is handled - expect(root.getAllByText('N/A').length).toEqual(1); + expect(root.getAllByText('n/a').length).toEqual(1); }); });