From 4181454a73b82180a4240a0789c5a196ac9291ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otgaar?= Date: Thu, 30 Oct 2025 13:05:56 +0100 Subject: [PATCH] feat: show robots page easier - quick connected sign. Quick reload - no need for manual reloads or anything. ref: N25B-142 --- package-lock.json | 126 +++++++++++++ src/pages/ConnectedRobots/ConnectedRobots.tsx | 176 ++---------------- 2 files changed, 144 insertions(+), 158 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4dc078..665dad5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1967,6 +1967,12 @@ "@tybys/wasm-util": "^0.10.0" } }, + "node_modules/@neodrag/react": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@neodrag/react/-/react-2.3.1.tgz", + "integrity": "sha512-mOVefo3mFmaVLs9PB5F5wMXnnclG81qjOaPHyf8YZUnw/Ciz0pAqyJDwDJk0nPTIK5I2x1JdjXSchGNdCxZNRQ==", + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3769,6 +3775,12 @@ "dev": true, "license": "MIT" }, + "node_modules/classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==", + "license": "MIT" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3951,6 +3963,111 @@ "devOptional": true, "license": "MIT" }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -7591,6 +7708,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", diff --git a/src/pages/ConnectedRobots/ConnectedRobots.tsx b/src/pages/ConnectedRobots/ConnectedRobots.tsx index abce238..a6f7ce7 100644 --- a/src/pages/ConnectedRobots/ConnectedRobots.tsx +++ b/src/pages/ConnectedRobots/ConnectedRobots.tsx @@ -1,178 +1,38 @@ -import { useEffect } from 'react' -import Logging from '../Logging/Logging'; - -// Define the robot type -type Robot = { - id: string; - name: string; - port: number; -}; - -// Define the expected arguments -type ConnectedRobotsProps = { - connectedRobots: Robot[]; - setConnectedRobots: React.Dispatch>; -}; - -export default function ConnectedRobots({ - connectedRobots, setConnectedRobots }: ConnectedRobotsProps) { +import { useEffect, useState } from 'react' +export default function ConnectedRobots() { + + const [connected, setConnected] = useState(null); useEffect(() => { - const eventSource = new EventSource("http://localhost:8000/sse"); + // We're excepting a stream of data like that looks like this: `data = False` or `data = True` + const eventSource = new EventSource("http://localhost:8000/robot/ping_stream"); eventSource.onmessage = (event) => { + + // Receive message and parse + console.log("received message:", event.data); try { const data = JSON.parse(event.data); - // Example: data = { event: "robot_connected", id: "pepper_robot1", name: "Pepper", port: 1234 } - if (data.event === "robot_connected") { - - // Safeguard id in request. - if (data.id === null || data.id === undefined) { - console.log(`Missing robot id in connection request. - Use format: 'data: {event = 'robot_connected', id = , (optional) name = , (optional) port = }'.`) - return () => eventSource.close(); - } - - // Safeguard duplicates - if (connectedRobots.some(robot => robot.id === data.id)) - console.log("connection request was sent for id: ", data.id, - " however this id was already present at current time"); - - // Add to connected robots while checking name and port for undefineds. - else { - const name = data.name ?? "no given name"; - const port = typeof data.port === "number" ? data.port : -1; - setConnectedRobots(robots => [...robots, { id: data.id, name: name, port: port }]); - } + // Set connected to value. + try { + setConnected(data) } - if (data.event === "robot_disconnected") { - // Safeguard id in request. - if (data.id === null || data.id === undefined) { - console.log("Missing robot id in connection request. Use format: 'data: {event = 'robot_disconnected', id = }'."); - return () => eventSource.close(); - } - - // Filter out same ids (should only be one) - setConnectedRobots(robots => robots.filter(robot => robot.id !== data.id)); - } - if (data.event === "robot_list") { - if (data.list === null || data.list === undefined) { - console.log("Missing list in robot_list request. Use format: 'data: {event = 'robot_list', list = }'."); - return () => eventSource.close(); - } - - // Set the robot list to the one found in CB - setConnectedRobots(data.list); + catch { + console.log("couldnt extract connected from incoming ping data") } } catch { - console.log("Unparsable SSE message:", event.data); + console.log("Ping message not in correct format:", event.data); } }; return () => eventSource.close(); - }, [connectedRobots]); + }); return (
-

Robots Connected

+

Is robot currently connected?

-

Connected Robots

-
    - {connectedRobots.map(robot => - // Map all the robots in an unordered list -
  • - {robot.name} (ID: {robot.id}, Port: {robot.port === -1 ? "No given port" : robot.port}) -
  • - )} -
-
-
-
- - - - -
+

Robot is currently: {connected == null ? "checking..." : (connected ? "connected! 🟢" : "not connected... 🔴")}

);