From 14c51a89a9bb3a678d42a0e7cc4231d0805a4d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Mon, 7 Aug 2023 15:48:46 +0200 Subject: [PATCH] feat: formatting of notification message - added function to get the value of a specified key in the serialized DataService object by the full access path - formatting notification message in "onNotify" function --- frontend/src/App.tsx | 39 +++++++++++++--- frontend/src/utils/nestedObjectUtils.ts | 45 +++++++++++++++++++ src/pydase/frontend/asset-manifest.json | 6 +-- src/pydase/frontend/index.html | 2 +- .../js/{main.f745d155.js => main.0683ca07.js} | 6 +-- ...CENSE.txt => main.0683ca07.js.LICENSE.txt} | 0 .../frontend/static/js/main.0683ca07.js.map | 1 + .../frontend/static/js/main.f745d155.js.map | 1 - src/pydase/utils/helpers.py | 5 +-- 9 files changed, 87 insertions(+), 18 deletions(-) create mode 100644 frontend/src/utils/nestedObjectUtils.ts rename src/pydase/frontend/static/js/{main.f745d155.js => main.0683ca07.js} (98%) rename src/pydase/frontend/static/js/{main.f745d155.js.LICENSE.txt => main.0683ca07.js.LICENSE.txt} (100%) create mode 100644 src/pydase/frontend/static/js/main.0683ca07.js.map delete mode 100644 src/pydase/frontend/static/js/main.f745d155.js.map diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 047fd9e..a7c778a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,4 @@ -import { useEffect, useReducer, useState } from 'react'; +import { useEffect, useReducer, useRef, useState } from 'react'; import { Navbar, Form, @@ -13,6 +13,7 @@ import { DataServiceJSON } from './components/DataServiceComponent'; import './App.css'; +import { getDataServiceJSONValueByPathAndKey } from './utils/nestedObjectUtils'; type ValueType = boolean | string | number | object; @@ -117,6 +118,8 @@ const reducer = (state: State, action: Action): State => { const App = () => { const [state, dispatch] = useReducer(reducer, null); + const stateRef = useRef(state); // Declare a reference to hold the current state + const [isInstantUpdate, setIsInstantUpdate] = useState(true); const [showSettings, setShowSettings] = useState(false); const [showNotification, setShowNotification] = useState(false); @@ -133,20 +136,37 @@ const App = () => { const handleShowSettings = () => setShowSettings(true); function onNotify(value: UpdateNotification) { - const currentTime = new Date(); - const timeString = currentTime.toISOString().substr(11, 8); + // Extracting data from the notification + const { parent_path, name, value: newValue } = value.data; + // Getting the current time in the required format + const timeString = new Date().toISOString().substring(11, 8); + + // Dispatching the update to the reducer dispatch({ type: 'UPDATE_ATTRIBUTE', - parent_path: value.data.parent_path, - name: value.data.name, - value: value.data.value + parent_path, + name, + value: newValue }); + + // Formatting the value if it is of type 'Quantity' + let notificationMsg: object | string = newValue; + const path = parent_path.concat('.', name); + if ( + getDataServiceJSONValueByPathAndKey(stateRef.current, path, 'type') === 'Quantity' + ) { + notificationMsg = `${newValue['magnitude']} ${newValue['unit']}`; + } + + // Creating a new notification const newNotification = { id: Math.random(), time: timeString, - text: `Attribute ${value.data.parent_path}.${value.data.name} updated to ${value.data.value}.` + text: `Attribute ${parent_path}.${name} updated to ${notificationMsg}.` }; + + // Adding the new notification to the list setNotifications((prevNotifications) => [newNotification, ...prevNotifications]); } @@ -163,6 +183,11 @@ const App = () => { setExceptions((prevNotifications) => [newNotification, ...prevNotifications]); } + // Keep the state reference up to date + useEffect(() => { + stateRef.current = state; + }, [state]); + useEffect(() => { // Fetch data from the API when the component mounts fetch(`http://${hostname}:${port}/service-properties`) diff --git a/frontend/src/utils/nestedObjectUtils.ts b/frontend/src/utils/nestedObjectUtils.ts new file mode 100644 index 0000000..797ece2 --- /dev/null +++ b/frontend/src/utils/nestedObjectUtils.ts @@ -0,0 +1,45 @@ +type Data = { + [key: string]: any; +}; + +const STANDARD_TYPES = [ + 'int', + 'float', + 'bool', + 'str', + 'Enum', + 'method', + 'NoneType', + 'Quantity' +]; + +export function getDataServiceJSONValueByPathAndKey( + data: Data, + path: string, + key = 'value' +): string { + // Split the path into parts + const parts = path.split(/\.|(?=\[\d+\])/); + parts.shift(); // Remove the first element + + // Traverse the dictionary according to the path parts + for (const part of parts) { + if (part.startsWith('[')) { + // List index + const idx = parseInt(part.substring(1, part.length - 1)); // Strip the brackets and convert to integer + data = data[idx]; + } else { + // Dictionary key + data = data[part]; + } + + // When the attribute is a class instance, the attributes are nested in the + // "value" key + if (!STANDARD_TYPES.includes(data['type'])) { + data = data['value']; + } + } + + // Return the value at the terminal point of the path + return data[key]; +} diff --git a/src/pydase/frontend/asset-manifest.json b/src/pydase/frontend/asset-manifest.json index 55583e4..283d964 100644 --- a/src/pydase/frontend/asset-manifest.json +++ b/src/pydase/frontend/asset-manifest.json @@ -1,13 +1,13 @@ { "files": { "main.css": "/static/css/main.d5ec2545.css", - "main.js": "/static/js/main.f745d155.js", + "main.js": "/static/js/main.0683ca07.js", "index.html": "/index.html", "main.d5ec2545.css.map": "/static/css/main.d5ec2545.css.map", - "main.f745d155.js.map": "/static/js/main.f745d155.js.map" + "main.0683ca07.js.map": "/static/js/main.0683ca07.js.map" }, "entrypoints": [ "static/css/main.d5ec2545.css", - "static/js/main.f745d155.js" + "static/js/main.0683ca07.js" ] } \ No newline at end of file diff --git a/src/pydase/frontend/index.html b/src/pydase/frontend/index.html index c25c921..6bd048b 100644 --- a/src/pydase/frontend/index.html +++ b/src/pydase/frontend/index.html @@ -1 +1 @@ -pydase App
\ No newline at end of file +pydase App
\ No newline at end of file diff --git a/src/pydase/frontend/static/js/main.f745d155.js b/src/pydase/frontend/static/js/main.0683ca07.js similarity index 98% rename from src/pydase/frontend/static/js/main.f745d155.js rename to src/pydase/frontend/static/js/main.0683ca07.js index d5e4b6a..874f9ac 100644 --- a/src/pydase/frontend/static/js/main.f745d155.js +++ b/src/pydase/frontend/static/js/main.0683ca07.js @@ -1,3 +1,3 @@ -/*! For license information please see main.f745d155.js.LICENSE.txt */ -!function(){var e={694:function(e,t){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t