mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-06-03 20:30:40 +02:00
feat: adding frontend notifications for attribute updates
This commit is contained in:
parent
86adba18da
commit
cf46dbbdde
@ -5,4 +5,14 @@ input.instantUpdate {
|
||||
.numberComponentButton {
|
||||
padding: 0.15em 6px !important;
|
||||
font-size: 0.70rem !important;
|
||||
}
|
||||
.navbarOffset {
|
||||
padding-top: 60px !important;
|
||||
right: 20;
|
||||
}
|
||||
/* .toastContainer {
|
||||
position: fixed;
|
||||
} */
|
||||
.notificationToast {
|
||||
background-color: rgba(114, 214, 253, 0.5) !important;
|
||||
}
|
@ -1,10 +1,18 @@
|
||||
import { useEffect, useReducer, useState } from 'react';
|
||||
import { Navbar, Form, Offcanvas, Container } from 'react-bootstrap';
|
||||
import {
|
||||
Navbar,
|
||||
Form,
|
||||
Offcanvas,
|
||||
Container,
|
||||
Toast,
|
||||
ToastContainer
|
||||
} from 'react-bootstrap';
|
||||
import { hostname, port, socket } from './socket';
|
||||
import {
|
||||
DataServiceComponent,
|
||||
DataServiceJSON
|
||||
} from './components/DataServiceComponent';
|
||||
import './App.css';
|
||||
|
||||
type ValueType = boolean | string | number | object;
|
||||
|
||||
@ -108,25 +116,38 @@ const App = () => {
|
||||
const [state, dispatch] = useReducer(reducer, null);
|
||||
const [isInstantUpdate, setIsInstantUpdate] = useState(true);
|
||||
const [showSettings, setShowSettings] = useState(false);
|
||||
const [showNotification, setShowNotification] = useState(true);
|
||||
const [notifications, setNotifications] = useState([]);
|
||||
|
||||
const removeNotificationById = (id: number) => {
|
||||
setNotifications((prevNotifications) =>
|
||||
prevNotifications.filter((n) => n.id !== id)
|
||||
);
|
||||
};
|
||||
|
||||
const handleCloseSettings = () => setShowSettings(false);
|
||||
const handleShowSettings = () => setShowSettings(true);
|
||||
|
||||
function onNotify(value: NotificationElement) {
|
||||
dispatch({
|
||||
type: 'UPDATE_ATTRIBUTE',
|
||||
parent_path: value.data.parent_path,
|
||||
name: value.data.name,
|
||||
value: value.data.value
|
||||
});
|
||||
const newNotification = {
|
||||
id: Math.random(),
|
||||
text: `Attribute ${value.data.parent_path}.${value.data.name} updated to ${value.data.value}.`
|
||||
};
|
||||
setNotifications((prevNotifications) => [newNotification, ...prevNotifications]);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// Fetch data from the API when the component mounts
|
||||
fetch(`http://${hostname}:${port}/service-properties`)
|
||||
.then((response) => response.json())
|
||||
.then((data: DataServiceJSON) => dispatch({ type: 'SET_DATA', data }));
|
||||
|
||||
function onNotify(value: NotificationElement) {
|
||||
dispatch({
|
||||
type: 'UPDATE_ATTRIBUTE',
|
||||
parent_path: value.data.parent_path,
|
||||
name: value.data.name,
|
||||
value: value.data.value
|
||||
});
|
||||
}
|
||||
|
||||
socket.on('notify', onNotify);
|
||||
|
||||
return () => {
|
||||
@ -147,7 +168,41 @@ const App = () => {
|
||||
</Container>
|
||||
</Navbar>
|
||||
|
||||
<Offcanvas show={showSettings} onHide={handleCloseSettings} placement="end">
|
||||
{showNotification && (
|
||||
<ToastContainer
|
||||
className="navbarOffset toastContainer"
|
||||
position="top-end"
|
||||
style={{ position: 'fixed' }}>
|
||||
{notifications.map((notification) => (
|
||||
<Toast
|
||||
className="notificationToast"
|
||||
key={notification.id}
|
||||
onClose={() => {
|
||||
removeNotificationById(notification.id);
|
||||
}}
|
||||
onClick={() => {
|
||||
removeNotificationById(notification.id);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
removeNotificationById(notification.id);
|
||||
}}
|
||||
show={true}
|
||||
autohide
|
||||
delay={2000}>
|
||||
<Toast.Header closeButton={false} className="notificationToast">
|
||||
<strong className="mr-auto">Notification</strong>
|
||||
</Toast.Header>
|
||||
<Toast.Body>{notification.text}</Toast.Body>
|
||||
</Toast>
|
||||
))}
|
||||
</ToastContainer>
|
||||
)}
|
||||
|
||||
<Offcanvas
|
||||
show={showSettings}
|
||||
onHide={handleCloseSettings}
|
||||
placement="end"
|
||||
style={{ zIndex: 9999 }}>
|
||||
<Offcanvas.Header closeButton>
|
||||
<Offcanvas.Title>Settings</Offcanvas.Title>
|
||||
</Offcanvas.Header>
|
||||
@ -158,11 +213,17 @@ const App = () => {
|
||||
type="switch"
|
||||
label="Enable Instant Update"
|
||||
/>
|
||||
<Form.Check
|
||||
checked={showNotification}
|
||||
onChange={(e) => setShowNotification(e.target.checked)}
|
||||
type="switch"
|
||||
label="Show Notifications"
|
||||
/>
|
||||
{/* Add any additional controls you want here */}
|
||||
</Offcanvas.Body>
|
||||
</Offcanvas>
|
||||
|
||||
<div className="App">
|
||||
<div className="App navbarOffset">
|
||||
<DataServiceComponent
|
||||
props={state as DataServiceJSON}
|
||||
isInstantUpdate={isInstantUpdate}
|
||||
|
@ -1,13 +1,13 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.e914def1.css",
|
||||
"main.js": "/static/js/main.e2e0686c.js",
|
||||
"main.css": "/static/css/main.b6b367bd.css",
|
||||
"main.js": "/static/js/main.1e89ddc5.js",
|
||||
"index.html": "/index.html",
|
||||
"main.e914def1.css.map": "/static/css/main.e914def1.css.map",
|
||||
"main.e2e0686c.js.map": "/static/js/main.e2e0686c.js.map"
|
||||
"main.b6b367bd.css.map": "/static/css/main.b6b367bd.css.map",
|
||||
"main.1e89ddc5.js.map": "/static/js/main.1e89ddc5.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.e914def1.css",
|
||||
"static/js/main.e2e0686c.js"
|
||||
"static/css/main.b6b367bd.css",
|
||||
"static/js/main.1e89ddc5.js"
|
||||
]
|
||||
}
|
@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site displaying a pydase UI."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>pydase App</title><script defer="defer" src="/static/js/main.e2e0686c.js"></script><link href="/static/css/main.e914def1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site displaying a pydase UI."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>pydase App</title><script defer="defer" src="/static/js/main.1e89ddc5.js"></script><link href="/static/css/main.b6b367bd.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
6
src/pydase/frontend/static/css/main.b6b367bd.css
Normal file
6
src/pydase/frontend/static/css/main.b6b367bd.css
Normal file
File diff suppressed because one or more lines are too long
1
src/pydase/frontend/static/css/main.b6b367bd.css.map
Normal file
1
src/pydase/frontend/static/css/main.b6b367bd.css.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
src/pydase/frontend/static/js/main.1e89ddc5.js
Normal file
3
src/pydase/frontend/static/js/main.1e89ddc5.js
Normal file
File diff suppressed because one or more lines are too long
1
src/pydase/frontend/static/js/main.1e89ddc5.js.map
Normal file
1
src/pydase/frontend/static/js/main.1e89ddc5.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user