diff options
Diffstat (limited to 'modern/src')
-rw-r--r-- | modern/src/Navigation.jsx | 2 | ||||
-rw-r--r-- | modern/src/SocketController.jsx | 8 | ||||
-rw-r--r-- | modern/src/reports/LogsPage.jsx | 46 | ||||
-rw-r--r-- | modern/src/reports/components/ReportsMenu.jsx | 44 | ||||
-rw-r--r-- | modern/src/resources/l10n/en.json | 1 | ||||
-rw-r--r-- | modern/src/store/session.js | 11 |
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; |