diff --git a/commit_and_push.sh b/commit_and_push.sh
new file mode 100755
index 0000000..554786f
--- /dev/null
+++ b/commit_and_push.sh
@@ -0,0 +1,7 @@
+git add *
+
+read -p "Commit message: " commit_message
+
+git commit -m "$commit_message"
+
+git push -u origin main
\ No newline at end of file
diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json
index b17472e..236dff8 100644
--- a/public/locales/de/translation.json
+++ b/public/locales/de/translation.json
@@ -178,13 +178,31 @@
"firmwareVersion": "Firmware Version",
"createdAt": "Erstellt am",
"actions": "Maßnahmen"
+ },
+ "status": {
+ "idle": "Inaktiv",
+ "processing": "Verarbeitung",
+ "connecting": "Verbinden",
+ "error": "Fehler",
+ "offline": "Offline"
+ },
+ "popconfirmEdit": {
+ "title": "Sind Sie sicher, dass Sie diesen Roboter bearbeiten wollen?",
+ "errorNotification": {
+ "message": "Roboter konnte nicht bearbeitet werden",
+ "description": "Name bereits vergeben"
+ }
+ },
+ "popconfirmDisconnect": {
+ "title": "Sind Sie sicher, dass Sie diesen Roboter trennen wollen?",
+ "description": "Der Roboter wird getrennt und kann nicht mehr für Aufträge verwendet werden"
}
},
"unauthorizedRobots": {
"header": "Nicht autorisierte Roboter",
"popconfirmDeny": {
"title": "Sind Sie sicher, dass Sie diesen Roboter ablehnen wollen?",
- "description": "Der Roboter wird getrennt und muss sich ernuet verbinden"
+ "description": "Der Roboter wird getrennt und muss sich erneut verbinden"
},
"popconfirmAuthorize": {
"title": "Sind Sie sicher, dass Sie diesen Roboter autorisieren wollen?",
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
index 79aee14..850740a 100644
--- a/public/locales/en/translation.json
+++ b/public/locales/en/translation.json
@@ -178,6 +178,24 @@
"firmwareVersion": "Firmware version",
"createdAt": "Created At",
"actions": "Actions"
+ },
+ "status": {
+ "idle": "Idle",
+ "processing": "Processing",
+ "connecting": "Connecting",
+ "error": "Error",
+ "offline": "Offline"
+ },
+ "popconfirmEdit": {
+ "title": "Are you sure you want to edit this robot?",
+ "errorNotification": {
+ "message": "Robot could not be edited",
+ "description": "Name already taken"
+ }
+ },
+ "popconfirmDisconnect": {
+ "title": "Are you sure you want to disconnect this robot?",
+ "description": "The robot will be disconnected and cannot be longer used for jobs"
}
},
"unauthorizedRobots": {
diff --git a/src/Pages/Robotics/Robots/index.js b/src/Pages/Robotics/Robots/index.js
index 27a05b4..6c32ea1 100644
--- a/src/Pages/Robotics/Robots/index.js
+++ b/src/Pages/Robotics/Robots/index.js
@@ -1,4 +1,12 @@
-import { Badge, Popconfirm, Space, Table, Typography } from "antd";
+import {
+ Badge,
+ Input,
+ Popconfirm,
+ Space,
+ Table,
+ Typography,
+ notification,
+} from "antd";
import { useTranslation } from "react-i18next";
import { useRoboticsRobotContext } from "../../../Contexts/RoboticsRobot";
import { useEffect, useRef, useState } from "react";
@@ -16,6 +24,8 @@ const ReceivedSSECommands = {
AddUnauthorizedRobot: 2,
AddRobot: 3,
RemoveUnauthorizedRobot: 4,
+ RemoveRobot: 5,
+ RobotUpdated: 6,
};
function getRobotTypeString(type) {
@@ -32,27 +42,46 @@ function getRobotTypeString(type) {
export default function Robots() {
const robotsContext = useRoboticsRobotContext();
const { t } = useTranslation();
+ const [notificationApi, notificationContextHolder] =
+ notification.useNotification();
const [robotsPaginationPage, setRobotsPaginationPage] = useState(1);
const [
unauthorizedRobotsPaginationPage,
setUnauthorizedRobotsPaginationPage,
] = useState(1);
+ const [selectedRobotName, setSelectedRobotName] = useState("");
const sseEventSource = useRef(null);
const getRobotStatusBadge = (status) => {
switch (status) {
case 1:
- return ;
+ return (
+
+ );
case 2:
- return ;
+ return (
+
+ );
case 3:
- return ;
+ return (
+
+ );
case 4:
- return ;
+ return (
+
+ );
case 5:
- return ;
+ return (
+
+ );
default:
return "Unknown";
}
@@ -116,8 +145,78 @@ export default function Robots() {
key: "actions",
render: (_, record) => (
- {t("common.text.edit")}
- {t("common.text.disconnect")}
+ setSelectedRobotName(e.target.value)}
+ minLength={Constants.GLOBALS.MIN_ROBOTICS_ROBOT_NAME_LENGTH}
+ maxLength={Constants.GLOBALS.MAX_ROBOTICS_ROBOT_NAME_LENGTH}
+ />
+ }
+ okButtonProps={{
+ disabled:
+ selectedRobotName.length <
+ Constants.GLOBALS.MIN_ROBOTICS_ROBOT_NAME_LENGTH ||
+ selectedRobotName.length >
+ Constants.GLOBALS.MAX_ROBOTICS_ROBOT_NAME_LENGTH,
+ }}
+ okText={t("common.button.confirm")}
+ cancelText={t("common.button.cancel")}
+ onConfirm={() =>
+ myFetch(
+ `/robot`,
+ "PATCH",
+ {
+ robotId: record.id,
+ name: selectedRobotName,
+ },
+ {},
+ myFetchContentType.JSON,
+ Constants.ROBOTICS_API_ADDRESS
+ ).catch((err) => {
+ if (err === 422) {
+ notificationApi["error"]({
+ message: t(
+ "robotics.robots.popconfirmEdit.errorNotification.message"
+ ),
+ description: t(
+ "robotics.robots.popconfirmEdit.errorNotification.description"
+ ),
+ });
+ }
+ })
+ }
+ >
+ setSelectedRobotName(record.name)}>
+ {t("common.text.edit")}
+
+
+
+
+ myFetch(
+ `/robot/${record.id}`,
+ "DELETE",
+ null,
+ {},
+ myFetchContentType.JSON,
+ Constants.ROBOTICS_API_ADDRESS
+ )
+ }
+ >
+ {t("common.text.disconnect")}
+
),
},
@@ -129,21 +228,27 @@ export default function Robots() {
const getRobotsTableItems = (robots) => {
let items = [];
- robots.forEach((robot) => {
+ robots.sort((a, b) => a.Status - b.Status);
+
+ robots.forEach((robot) =>
items.push({
key: robot.Id,
id: robot.Id,
type: getRobotTypeString(robot.Type),
name: robot.Name,
status: getRobotStatusBadge(robot.Status),
- currentJob: robot.CurrentJob,
+ currentJob:
+ robot.CurrentJobId === ""
+ ? Constants.TEXT_EMPTY_PLACEHOLDER
+ : robot.CurrentJobId,
jobsWaiting: robot.JobsWaitingCount,
address: robot.Address,
firmwareVersion: robot.FirmwareVersion,
connectedAt: FormatDatetime(robot.ConnectedAt),
+ createdAt: FormatDatetime(robot.CreatedAt),
actions: robot.Actions,
- });
- });
+ })
+ );
return items;
};
@@ -170,6 +275,11 @@ export default function Robots() {
dataIndex: "connectedAt",
key: "connectedAt",
},
+ {
+ title: t("robotics.robots.column.firmwareVersion"),
+ dataIndex: "firmwareVersion",
+ key: "firmwareVersion",
+ },
{
title: t("robotics.robots.column.actions"),
dataIndex: "actions",
@@ -192,9 +302,7 @@ export default function Robots() {
{},
myFetchContentType.JSON,
Constants.ROBOTICS_API_ADDRESS
- ).then((data) => {
- console.log("data", data);
- })
+ )
}
>
{t("common.text.deny")}
@@ -216,9 +324,7 @@ export default function Robots() {
{},
myFetchContentType.JSON,
Constants.ROBOTICS_API_ADDRESS
- ).then((data) => {
- console.log("data", data);
- })
+ )
}
>
{t("common.text.authorize")}
@@ -241,6 +347,7 @@ export default function Robots() {
type: getRobotTypeString(robot.Type),
address: robot.Address,
connectedAt: FormatDatetime(robot.ConnectedAt),
+ firmwareVersion: robot.FirmwareVersion,
actions: robot.Actions,
});
});
@@ -293,12 +400,8 @@ export default function Robots() {
robotsContext.setRobots((arr) => {
const newArr = [...arr];
- console.log("arr", arr);
-
const index = arr.findIndex((x) => x.Id === body.RobotId);
- console.log("index", index);
-
if (index !== -1) {
newArr[index].Status = body.Status;
}
@@ -335,6 +438,19 @@ export default function Robots() {
return newArr;
});
+
+ // remove from unauthorized robots
+ robotsContext.setUnauthorizedRobots((arr) => {
+ const newArr = [...arr];
+
+ const index = arr.findIndex((x) => x.Id === body.Id);
+
+ if (index !== -1) {
+ newArr.splice(index, 1);
+ }
+
+ return newArr;
+ });
break;
case ReceivedSSECommands.RemoveUnauthorizedRobot:
robotsContext.setUnauthorizedRobots((arr) => {
@@ -349,6 +465,32 @@ export default function Robots() {
return newArr;
});
break;
+ case ReceivedSSECommands.RemoveRobot:
+ robotsContext.setRobots((arr) => {
+ const newArr = [...arr];
+
+ const index = arr.findIndex((x) => x.Id === body);
+
+ if (index !== -1) {
+ newArr.splice(index, 1);
+ }
+
+ return newArr;
+ });
+ break;
+ case ReceivedSSECommands.RobotUpdated:
+ robotsContext.setRobots((arr) => {
+ const newArr = [...arr];
+
+ const index = arr.findIndex((x) => x.Id === body.RobotId);
+
+ if (index !== -1) {
+ newArr[index].Name = body.Name;
+ }
+
+ return newArr;
+ });
+ break;
default:
break;
}
@@ -365,6 +507,8 @@ export default function Robots() {
return (
<>
+ {notificationContextHolder}
+
{t("robotics.robots.header")} ({robotsContext.robots.length})
diff --git a/src/utils.js b/src/utils.js
index 6a05b24..3ba6c79 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -102,6 +102,8 @@ export const Constants = {
MAX_LOG_MANAGER_DISPLAY_NAME_LENGTH: 16,
MIN_LOG_MANAGER_ADDRESS_LENGTH: 3,
MAX_LOG_MANAGER_ADDRESS_LENGTH: 100,
+ MIN_ROBOTICS_ROBOT_NAME_LENGTH: 2,
+ MAX_ROBOTICS_ROBOT_NAME_LENGTH: 30,
},
MAX_AVATAR_SIZE: 5 * 1024 * 1024,
ACCEPTED_AVATAR_FILE_TYPES: [
@@ -1390,7 +1392,7 @@ export function myFetch(
window.location.href = "/";
}
- return;
+ throw response.status;
}
// check if response is json