Philipp Heckel 4 лет назад
Родитель
Сommit
dd1a85e733
3 измененных файлов с 71 добавлено и 9 удалено
  1. 37 0
      web/src/app/Storage.js
  2. 3 3
      web/src/app/WsConnection.js
  3. 31 6
      web/src/components/App.js

+ 37 - 0
web/src/app/Storage.js

@@ -0,0 +1,37 @@
+import {topicUrl} from "./utils";
+import Subscription from "./Subscription";
+
+const LocalStorage = {
+    getSubscriptions() {
+        const subscriptions = {};
+        const rawSubscriptions = localStorage.getItem('subscriptions');
+        if (rawSubscriptions === null) {
+            return {};
+        }
+        try {
+            const serializedSubscriptions = JSON.parse(rawSubscriptions);
+            serializedSubscriptions.forEach(s => {
+                const subscription = new Subscription(s.baseUrl, s.topic);
+                subscription.notifications = s.notifications;
+                subscriptions[topicUrl(s.baseUrl, s.topic)] = subscription;
+            });
+            return subscriptions;
+        } catch (e) {
+            console.log("LocalStorage", `Unable to deserialize subscriptions: ${e.message}`)
+            return {};
+        }
+    },
+    saveSubscriptions(subscriptions) {
+        const serializedSubscriptions = Object.keys(subscriptions).map(k => {
+            const subscription = subscriptions[k];
+            return {
+                baseUrl: subscription.baseUrl,
+                topic: subscription.topic,
+                notifications: subscription.notifications
+            }
+        });
+        localStorage.setItem('subscriptions', JSON.stringify(serializedSubscriptions));
+    }
+};
+
+export default LocalStorage;

+ 3 - 3
web/src/app/WsConnection.js

@@ -1,10 +1,10 @@
 
 
 export default class WsConnection {
 export default class WsConnection {
     id = '';
     id = '';
-    constructor(subscription, onNotification) {
+    constructor(subscription, onChange) {
         this.id = subscription.id;
         this.id = subscription.id;
         this.subscription = subscription;
         this.subscription = subscription;
-        this.onNotification = onNotification;
+        this.onChange = onChange;
         this.ws = null;
         this.ws = null;
     }
     }
     start() {
     start() {
@@ -26,7 +26,7 @@ export default class WsConnection {
                 }
                 }
                 console.log('adding')
                 console.log('adding')
                 this.subscription.addNotification(data);
                 this.subscription.addNotification(data);
-                this.onNotification(this.subscription);
+                this.onChange(this.subscription);
             } catch (e) {
             } catch (e) {
                 console.log(this.id, `[message] Error handling message: ${e}`);
                 console.log(this.id, `[message] Error handling message: ${e}`);
             }
             }

+ 31 - 6
web/src/components/App.js

@@ -1,5 +1,5 @@
 import * as React from 'react';
 import * as React from 'react';
-import {useState} from 'react';
+import {useEffect, useState} from 'react';
 import Container from '@mui/material/Container';
 import Container from '@mui/material/Container';
 import Typography from '@mui/material/Typography';
 import Typography from '@mui/material/Typography';
 import Box from '@mui/material/Box';
 import Box from '@mui/material/Box';
@@ -27,6 +27,7 @@ import Card from "@mui/material/Card";
 import {CardContent, Stack} from "@mui/material";
 import {CardContent, Stack} from "@mui/material";
 import AddDialog from "./AddDialog";
 import AddDialog from "./AddDialog";
 import theme from "./theme";
 import theme from "./theme";
+import LocalStorage from "../app/Storage";
 
 
 const drawerWidth = 240;
 const drawerWidth = 240;
 
 
@@ -130,32 +131,56 @@ const NotificationItem = (props) => {
 }
 }
 
 
 const App = () => {
 const App = () => {
+    console.log("Launching App component");
+
     const [drawerOpen, setDrawerOpen] = useState(true);
     const [drawerOpen, setDrawerOpen] = useState(true);
-    const [subscriptions, setSubscriptions] = useState({});
-    const [selectedSubscription, setSelectedSubscription] = useState(null);
+    const [subscriptions, setSubscriptions] = useState(LocalStorage.getSubscriptions());
     const [connections, setConnections] = useState({});
     const [connections, setConnections] = useState({});
+    const [selectedSubscription, setSelectedSubscription] = useState(null);
     const [addDialogOpen, setAddDialogOpen] = useState(false);
     const [addDialogOpen, setAddDialogOpen] = useState(false);
     const subscriptionChanged = (subscription) => {
     const subscriptionChanged = (subscription) => {
         setSubscriptions(prev => ({...prev, [subscription.id]: subscription})); // Fake-replace
         setSubscriptions(prev => ({...prev, [subscription.id]: subscription})); // Fake-replace
     };
     };
     const handleAddSubmit = (subscription) => {
     const handleAddSubmit = (subscription) => {
-        setAddDialogOpen(false);
         const connection = new WsConnection(subscription, subscriptionChanged);
         const connection = new WsConnection(subscription, subscriptionChanged);
+        setAddDialogOpen(false);
         setSubscriptions(prev => ({...prev, [subscription.id]: subscription}));
         setSubscriptions(prev => ({...prev, [subscription.id]: subscription}));
-        setConnections(prev => ({...prev, [connection.id]: connection}));
+        setConnections(prev => ({...prev, [subscription.id]: connection}));
         connection.start();
         connection.start();
     };
     };
     const handleAddCancel = () => {
     const handleAddCancel = () => {
+        console.log(`Cancel clicked`)
         setAddDialogOpen(false);
         setAddDialogOpen(false);
     }
     }
     const handleSubscriptionClick = (subscriptionId) => {
     const handleSubscriptionClick = (subscriptionId) => {
-        console.log(`handleSubscriptionClick ${subscriptionId}`)
+        console.log(`Selected subscription ${subscriptionId}`)
         setSelectedSubscription(subscriptions[subscriptionId]);
         setSelectedSubscription(subscriptions[subscriptionId]);
     };
     };
     const notifications = (selectedSubscription !== null) ? selectedSubscription.notifications : [];
     const notifications = (selectedSubscription !== null) ? selectedSubscription.notifications : [];
     const toggleDrawer = () => {
     const toggleDrawer = () => {
         setDrawerOpen(!drawerOpen);
         setDrawerOpen(!drawerOpen);
     };
     };
+    useEffect(() => {
+        console.log("Starting connections");
+        Object.keys(subscriptions).forEach(topicUrl => {
+            console.log(`Starting connection for ${topicUrl}`);
+            const subscription = subscriptions[topicUrl];
+            const connection = new WsConnection(subscription, subscriptionChanged);
+            connection.start();
+        });
+        return () => {
+            console.log("Stopping connections");
+            Object.keys(connections).forEach(topicUrl => {
+                console.log(`Stopping connection for ${topicUrl}`);
+                const connection = connections[topicUrl];
+                connection.cancel();
+            });
+        };
+    }, [/* only on initial render */]);
+    useEffect(() => {
+        console.log(`Saving subscriptions`);
+        LocalStorage.saveSubscriptions(subscriptions);
+    }, [subscriptions]);
     return (
     return (
         <ThemeProvider theme={theme}>
         <ThemeProvider theme={theme}>
             <Box sx={{ display: 'flex' }}>
             <Box sx={{ display: 'flex' }}>