diff --git a/src/components/panels/MosaicDashboard.tsx b/src/components/panels/MosaicDashboard.tsx
index deddd80..0bf130c 100644
--- a/src/components/panels/MosaicDashboard.tsx
+++ b/src/components/panels/MosaicDashboard.tsx
@@ -33,79 +33,50 @@ import DriveThrottlePanel from './DriveThrottlePanel';
import { ROVER_IP } from '@/constants';
-type TileType =
- | 'mapView'
- | 'rosMonitor'
- | 'waypointList'
- | 'videoControls'
- | 'rtpStats'
- | 'orientationDisplay'
- | 'goalSetter'
- | 'networkHealthMonitor'
- | 'motorStatusPanel'
- | 'driveThrottlePanel'
- | 'nodeStatusPanel'
- | 'antennaControlPanel'
- | 'scienceControlPanel'
- | 'scienceSensorPanel'
- | 'pdbRails'
- | 'armControlPanel'
- | 'webRTCClient'
- | 'timerPanel'
- | 'headlightControlPanel'
- | 'morseTransmissionPanel'
- | 'echoPanel'
- ;
+interface TileDefinition {
+ title: string;
+ render: () => ReactElement;
+}
+const TILE_REGISTRY = {
+ mapView: {
+ title: 'Map View',
+ render: () => (
+
+
+
+ ),
+ },
+ rosMonitor: { title: 'System Telemetry', render: () => },
+ networkHealthMonitor: { title: 'Connection Health', render: () => },
+ orientationDisplay: { title: 'Rover Orientation', render: () => },
+ videoControls: { title: 'Video Stream', render: () => },
+ rtpStats: { title: 'RTP Statistics', render: () => },
+ driveThrottlePanel: { title: 'Drive Throttle', render: () => },
+ waypointList: { title: 'Waypoint List', render: () => },
+ goalSetter: { title: 'Nav2', render: () => },
+ motorStatusPanel: { title: 'Motor Status', render: () => },
+ nodeStatusPanel: { title: 'Node Status', render: () => },
+ antennaControlPanel: { title: 'Antenna Control', render: () => },
+ scienceControlPanel: { title: 'Science Motor Control', render: () => },
+ scienceSensorPanel: { title: 'Science Sensor Readouts', render: () => },
+ pdbRails: { title: 'PDB Rails', render: () => },
+ armControlPanel: { title: 'Arm Control', render: () => },
+ webRTCClient: {
+ title: 'WebRTC Client',
+ render: () => ,
+ },
+ timerPanel: { title: 'Multi-Timer', render: () => },
+ headlightControlPanel: { title: 'Headlights', render: () => },
+ morseTransmissionPanel: { title: 'Morse Transmission', render: () => },
+ echoPanel: { title: 'Topic Echo', render: () => },
+} satisfies Record;
+
+type TileType = keyof typeof TILE_REGISTRY;
type TileId = `${TileType}:${number}`;
-const TILE_DISPLAY_NAMES: Record = {
- mapView: 'Map View',
- rosMonitor: 'System Telemetry',
- waypointList: 'Waypoint List',
- videoControls: 'Video Stream',
- rtpStats: 'RTP Statistics',
- driveThrottlePanel: 'Drive Throttle',
- orientationDisplay: 'Rover Orientation',
- goalSetter: 'Nav2',
- networkHealthMonitor: 'Connection Health',
- motorStatusPanel: 'Motor Status',
- nodeStatusPanel: 'Node Status',
- antennaControlPanel: 'Antenna Control',
- scienceControlPanel: 'Science Motor Control',
- scienceSensorPanel: 'Science Sensor Readouts',
- pdbRails: 'PDB Rails',
- armControlPanel: 'Arm Control',
- webRTCClient: 'WebRTC Client',
- timerPanel: 'Multi-Timer',
- headlightControlPanel: 'Headlights',
- morseTransmissionPanel: 'Morse Transmission',
- echoPanel: 'Topic Echo',
-};
-
-const ALL_TILE_TYPES: TileType[] = [
- 'mapView',
- 'rosMonitor',
- 'networkHealthMonitor',
- 'orientationDisplay',
- 'videoControls',
- 'rtpStats',
- 'driveThrottlePanel',
- 'waypointList',
- 'goalSetter',
- 'motorStatusPanel',
- 'nodeStatusPanel',
- 'antennaControlPanel',
- 'scienceControlPanel',
- 'scienceSensorPanel',
- 'pdbRails',
- 'armControlPanel',
- 'webRTCClient',
- 'timerPanel',
- 'headlightControlPanel',
- 'morseTransmissionPanel',
- 'echoPanel',
-];
+// Object.keys preserves insertion order for string keys
+const ALL_TILE_TYPES = Object.keys(TILE_REGISTRY) as TileType[];
function tileTypeOf(id: TileId): TileType {
return id.split(':', 1)[0] as TileType;
@@ -277,7 +248,7 @@ const Controls = memo<{
{ALL_TILE_TYPES.map((t) => (
))}
@@ -349,158 +320,30 @@ const MosaicDashboard: React.FC = () => {
path: MosaicPath;
additionalControls: ReactElement;
} = {
- title: TILE_DISPLAY_NAMES[type],
+ title: TILE_REGISTRY[type]?.title ?? type,
path,
additionalControls: controls,
};
- switch (type) {
- case 'mapView':
- return (
-
-
-
-
-
- );
-
- case 'waypointList':
- return (
-
-
-
- );
-
- case 'videoControls':
- return (
-
-
-
- );
-
- case 'rtpStats':
- return (
-
-
-
- );
-
- case 'driveThrottlePanel':
- return (
-
-
-
- );
-
- case 'rosMonitor':
- return (
-
-
-
- );
-
- case 'networkHealthMonitor':
- return (
-
-
-
- );
-
- case 'orientationDisplay':
- return (
-
-
-
- );
-
- case 'goalSetter':
- return (
-
-
-
- );
-
- case 'motorStatusPanel':
- return (
-
-
-
- );
-
- case 'nodeStatusPanel':
- return (
-
-
-
- );
-
- case 'antennaControlPanel':
- return (
-
-
-
- );
- case 'scienceControlPanel':
- return (
-
-
-
- );
- case 'scienceSensorPanel':
- return(
-
-
-
- );
- case 'pdbRails':
- return(
-
-
-
- );
- case 'armControlPanel':
- return(
-
-
-
- );
- case 'webRTCClient':
- return(
-
-
-
- );
- case 'timerPanel':
- return (
-
-
-
- );
- case 'headlightControlPanel':
- return (
-
-
-
- );
-
- case 'morseTransmissionPanel':
- return (
-
-
-
- );
- case 'echoPanel':
- return (
-
-
-
- );
-
- default:
- return Unknown tile
;
- }
+ return (
+
+ {TILE_REGISTRY[type]?.render() ?? (
+
+ Unknown tile
+
+ )}
+
+ );
};
if (!mosaicLayout) return null;