aboutsummaryrefslogtreecommitdiff
path: root/modern/src
diff options
context:
space:
mode:
Diffstat (limited to 'modern/src')
-rw-r--r--modern/src/Navigation.jsx2
-rw-r--r--modern/src/SocketController.jsx8
-rw-r--r--modern/src/reports/LogsPage.jsx46
-rw-r--r--modern/src/reports/components/ReportsMenu.jsx44
-rw-r--r--modern/src/resources/l10n/en.json1
-rw-r--r--modern/src/store/session.js11
6 files changed, 92 insertions, 20 deletions
diff --git a/modern/src/Navigation.jsx b/modern/src/Navigation.jsx
index ad02106c..731eeb62 100644
--- a/modern/src/Navigation.jsx
+++ b/modern/src/Navigation.jsx
@@ -54,6 +54,7 @@ import ScheduledPage from './reports/ScheduledPage';
import DeviceConnectionsPage from './settings/DeviceConnectionsPage';
import GroupConnectionsPage from './settings/GroupConnectionsPage';
import UserConnectionsPage from './settings/UserConnectionsPage';
+import LogsPage from './reports/LogsPage';
const Navigation = () => {
const navigate = useNavigate();
@@ -157,6 +158,7 @@ const Navigation = () => {
<Route path="trip" element={<TripReportPage />} />
<Route path="scheduled" element={<ScheduledPage />} />
<Route path="statistics" element={<StatisticsPage />} />
+ <Route path="logs" element={<LogsPage />} />
</Route>
</Route>
</Routes>
diff --git a/modern/src/SocketController.jsx b/modern/src/SocketController.jsx
index 7dd073fd..fe39d2b7 100644
--- a/modern/src/SocketController.jsx
+++ b/modern/src/SocketController.jsx
@@ -20,6 +20,7 @@ const SocketController = () => {
const authenticated = useSelector((state) => !!state.session.user);
const devices = useSelector((state) => state.devices.items);
+ const includeLogs = useSelector((state) => state.session.includeLogs);
const socketRef = useRef();
@@ -76,9 +77,16 @@ const SocketController = () => {
}
setEvents(data.events);
}
+ if (data.logs) {
+ dispatch(sessionActions.updateLogs(data.logs));
+ }
};
};
+ useEffect(() => {
+ socketRef.current?.send(JSON.stringify({ logs: includeLogs }));
+ }, [socketRef, includeLogs]);
+
useEffectAsync(async () => {
if (authenticated) {
const response = await fetch('/api/devices');
diff --git a/modern/src/reports/LogsPage.jsx b/modern/src/reports/LogsPage.jsx
new file mode 100644
index 00000000..3a72f81b
--- /dev/null
+++ b/modern/src/reports/LogsPage.jsx
@@ -0,0 +1,46 @@
+import React, { useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import {
+ Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import { useTranslation } from '../common/components/LocalizationProvider';
+import PageLayout from '../common/components/PageLayout';
+import ReportsMenu from './components/ReportsMenu';
+import { sessionActions } from '../store';
+
+const LogsPage = () => {
+ const dispatch = useDispatch();
+ const t = useTranslation();
+
+ useEffect(() => {
+ dispatch(sessionActions.enableLogs(true));
+ return () => dispatch(sessionActions.enableLogs(false));
+ }, []);
+
+ const items = useSelector((state) => state.session.logs);
+
+ return (
+ <PageLayout menu={<ReportsMenu />} breadcrumbs={['reportTitle', 'statisticsTitle']}>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell>{t('deviceIdentifier')}</TableCell>
+ <TableCell>{t('positionProtocol')}</TableCell>
+ <TableCell>{t('commandData')}</TableCell>
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {items.map((item, index) => (
+ <TableRow key={index}>
+ <TableCell>{item.uniqueId}</TableCell>
+ <TableCell>{item.port}</TableCell>
+ <TableCell>{item.data}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </PageLayout>
+ );
+};
+
+export default LogsPage;
diff --git a/modern/src/reports/components/ReportsMenu.jsx b/modern/src/reports/components/ReportsMenu.jsx
index a6c38578..76564e11 100644
--- a/modern/src/reports/components/ReportsMenu.jsx
+++ b/modern/src/reports/components/ReportsMenu.jsx
@@ -12,6 +12,7 @@ import TrendingUpIcon from '@mui/icons-material/TrendingUp';
import BarChartIcon from '@mui/icons-material/BarChart';
import RouteIcon from '@mui/icons-material/Route';
import EventRepeatIcon from '@mui/icons-material/EventRepeat';
+import NotesIcon from '@mui/icons-material/Notes';
import { Link, useLocation } from 'react-router-dom';
import { useTranslation } from '../../common/components/LocalizationProvider';
import { useAdministrator, useRestriction } from '../../common/util/permissions';
@@ -83,26 +84,29 @@ const ReportsMenu = () => {
icon={<RouteIcon />}
/>
</List>
- {(admin || !readonly) && (
- <>
- <Divider />
- <List>
- <MenuItem
- title={t('reportScheduled')}
- link="/reports/scheduled"
- icon={<EventRepeatIcon />}
- />
- {admin && (
- <MenuItem
- title={t('statisticsTitle')}
- link="/reports/statistics"
- icon={<BarChartIcon />}
- selected={location.pathname === '/reports/statistics'}
- />
- )}
- </List>
- </>
- )}
+ <Divider />
+ <List>
+ <MenuItem
+ title={t('sharedLogs')}
+ link="/reports/logs"
+ icon={<NotesIcon />}
+ />
+ {!readonly && (
+ <MenuItem
+ title={t('reportScheduled')}
+ link="/reports/scheduled"
+ icon={<EventRepeatIcon />}
+ />
+ )}
+ {admin && (
+ <MenuItem
+ title={t('statisticsTitle')}
+ link="/reports/statistics"
+ icon={<BarChartIcon />}
+ selected={location.pathname === '/reports/statistics'}
+ />
+ )}
+ </List>
</>
);
};
diff --git a/modern/src/resources/l10n/en.json b/modern/src/resources/l10n/en.json
index 0f57b52a..dc34efa0 100644
--- a/modern/src/resources/l10n/en.json
+++ b/modern/src/resources/l10n/en.json
@@ -100,6 +100,7 @@
"sharedColumns": "Columns",
"sharedDropzoneText": "Drag and drop a file here or click",
"sharedLinkCopied": "Link copied",
+ "sharedLogs": "Logs",
"calendarSimple": "Simple",
"calendarRecurrence": "Recurrence",
"calendarOnce": "Once",
diff --git a/modern/src/store/session.js b/modern/src/store/session.js
index a95cfec8..bfe94a41 100644
--- a/modern/src/store/session.js
+++ b/modern/src/store/session.js
@@ -6,6 +6,8 @@ const { reducer, actions } = createSlice({
server: null,
user: null,
socket: null,
+ includeLogs: false,
+ logs: [],
positions: {},
history: {},
},
@@ -19,6 +21,15 @@ const { reducer, actions } = createSlice({
updateSocket(state, action) {
state.socket = action.payload;
},
+ enableLogs(state, action) {
+ state.includeLogs = action.payload;
+ if (!action.payload) {
+ state.logs = [];
+ }
+ },
+ updateLogs(state, action) {
+ state.logs.push(...action.payload);
+ },
updatePositions(state, action) {
const liveRoutes = state.user.attributes.mapLiveRoutes || state.server.attributes.mapLiveRoutes || 'none';
const liveRoutesLimit = state.user.attributes['web.liveRouteLength'] || state.server.attributes['web.liveRouteLength'] || 10;