feat: adding frontend notifications for attribute updates

This commit is contained in:
Mose Müller 2023-08-03 11:59:46 +02:00
parent 86adba18da
commit cf46dbbdde
13 changed files with 101 additions and 30 deletions

View File

@ -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;
}

View File

@ -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}

View File

@ -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"
]
}

View File

@ -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>

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

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long