mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-21 16:50:02 +02:00
frontend: updates reducer to process serialized values
This commit is contained in:
parent
f693fa9ba2
commit
4a43bda5e2
@ -8,96 +8,32 @@ import {
|
|||||||
import './App.css';
|
import './App.css';
|
||||||
import { Notifications } from './components/NotificationsComponent';
|
import { Notifications } from './components/NotificationsComponent';
|
||||||
import { ConnectionToast } from './components/ConnectionToast';
|
import { ConnectionToast } from './components/ConnectionToast';
|
||||||
|
import { SerializedValue, setNestedValueByPath, State } from './utils/stateUtils';
|
||||||
|
|
||||||
type ValueType = boolean | string | number | object;
|
|
||||||
|
|
||||||
type State = DataServiceJSON | null;
|
|
||||||
type Action =
|
type Action =
|
||||||
| { type: 'SET_DATA'; data: DataServiceJSON }
|
| { type: 'SET_DATA'; data: State }
|
||||||
| { type: 'UPDATE_ATTRIBUTE'; parentPath: string; name: string; value: ValueType };
|
| {
|
||||||
|
type: 'UPDATE_ATTRIBUTE';
|
||||||
|
parentPath: string;
|
||||||
|
name: string;
|
||||||
|
value: SerializedValue;
|
||||||
|
};
|
||||||
type UpdateMessage = {
|
type UpdateMessage = {
|
||||||
data: { parent_path: string; name: string; value: object };
|
data: { parent_path: string; name: string; value: SerializedValue };
|
||||||
};
|
};
|
||||||
type ExceptionMessage = {
|
type ExceptionMessage = {
|
||||||
data: { exception: string; type: string };
|
data: { exception: string; type: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* A function to update a specific property in a deeply nested object.
|
|
||||||
* The property to be updated is specified by a path array.
|
|
||||||
*
|
|
||||||
* Each path element can be a regular object key or an array index of the
|
|
||||||
* form "attribute[index]", where "attribute" is the key of the array in
|
|
||||||
* the object and "index" is the index of the element in the array.
|
|
||||||
*
|
|
||||||
* For array indices, the element at the specified index in the array is
|
|
||||||
* updated.
|
|
||||||
*
|
|
||||||
* If the property to be updated is an object or an array, it is updated
|
|
||||||
* recursively.
|
|
||||||
*/
|
|
||||||
function updateNestedObject(path: Array<string>, obj: object, value: ValueType) {
|
|
||||||
// Base case: If the path is empty, return the new value.
|
|
||||||
// This means we've reached the nested property to be updated.
|
|
||||||
if (path.length === 0) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursive case: If the path is not empty, split it into the first key and the rest
|
|
||||||
// of the path.
|
|
||||||
const [first, ...rest] = path;
|
|
||||||
|
|
||||||
// Check if 'first' is an array index.
|
|
||||||
const indexMatch = first.match(/^(\w+)\[(\d+)\]$/);
|
|
||||||
|
|
||||||
// If 'first' is an array index of the form "attribute[index]", then update the
|
|
||||||
// element at the specified index in the array. Otherwise, update the property
|
|
||||||
// specified by 'first' in the object.
|
|
||||||
if (indexMatch) {
|
|
||||||
const attribute = indexMatch[1];
|
|
||||||
const index = parseInt(indexMatch[2]);
|
|
||||||
|
|
||||||
if (Array.isArray(obj[attribute]?.value)) {
|
|
||||||
return {
|
|
||||||
...obj,
|
|
||||||
[attribute]: {
|
|
||||||
...obj[attribute],
|
|
||||||
value: obj[attribute].value.map((item, i) =>
|
|
||||||
i === index
|
|
||||||
? {
|
|
||||||
...item,
|
|
||||||
value: updateNestedObject(rest, item.value || {}, value)
|
|
||||||
}
|
|
||||||
: item
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
`Expected ${attribute}.value to be an array, but received ${typeof obj[
|
|
||||||
attribute
|
|
||||||
]?.value}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...obj,
|
|
||||||
[first]: {
|
|
||||||
...obj[first],
|
|
||||||
value: updateNestedObject(rest, obj[first]?.value || {}, value)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const reducer = (state: State, action: Action): State => {
|
const reducer = (state: State, action: Action): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SET_DATA':
|
case 'SET_DATA':
|
||||||
return action.data;
|
return action.data;
|
||||||
case 'UPDATE_ATTRIBUTE': {
|
case 'UPDATE_ATTRIBUTE': {
|
||||||
const path = action.parentPath.split('.').slice(1).concat(action.name);
|
const pathList = action.parentPath.split('.').slice(1).concat(action.name);
|
||||||
|
const joinedPath = pathList.join('.');
|
||||||
|
|
||||||
return updateNestedObject(path, state, action.value);
|
return setNestedValueByPath(state, joinedPath, action.value);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error();
|
throw new Error();
|
||||||
@ -137,7 +73,7 @@ const App = () => {
|
|||||||
// Fetch data from the API when the client connects
|
// Fetch data from the API when the client connects
|
||||||
fetch(`http://${hostname}:${port}/service-properties`)
|
fetch(`http://${hostname}:${port}/service-properties`)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data: DataServiceJSON) => dispatch({ type: 'SET_DATA', data }));
|
.then((data: State) => dispatch({ type: 'SET_DATA', data }));
|
||||||
setConnectionStatus('connected');
|
setConnectionStatus('connected');
|
||||||
});
|
});
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user