aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2021-07-10 15:24:10 -0700
committerAnton Tananaev <anton.tananaev@gmail.com>2021-07-10 15:24:10 -0700
commit0512964d71a25c172735f2149ef60c3a8b20f683 (patch)
treef47b42326a7e6a0eaa2715ca8066cb3ca7e7bb90
parent627cf95d59f625dcb0544bfd4c067d99dee4bb93 (diff)
downloadetbsa-traccar-web-0512964d71a25c172735f2149ef60c3a8b20f683.tar.gz
etbsa-traccar-web-0512964d71a25c172735f2149ef60c3a8b20f683.tar.bz2
etbsa-traccar-web-0512964d71a25c172735f2149ef60c3a8b20f683.zip
Use modified airbnb eslint
-rw-r--r--modern/.eslintrc.js18
-rw-r--r--modern/craco.config.js8
-rw-r--r--modern/package.json11
-rw-r--r--modern/src/App.js68
-rw-r--r--modern/src/CachingController.js22
-rw-r--r--modern/src/DevicePage.js97
-rw-r--r--modern/src/DevicesList.js15
-rw-r--r--modern/src/EditCollectionView.js27
-rw-r--r--modern/src/EditItemView.js18
-rw-r--r--modern/src/GeofencePage.js22
-rw-r--r--modern/src/GeofencesList.js12
-rw-r--r--modern/src/GeofencesPage.js13
-rw-r--r--modern/src/Logo.js47
-rw-r--r--modern/src/MainPage.js11
-rw-r--r--modern/src/MainToolbar.js38
-rw-r--r--modern/src/PositionPage.js31
-rw-r--r--modern/src/RegisterDialog.js62
-rw-r--r--modern/src/RemoveDialog.js9
-rw-r--r--modern/src/SocketController.js30
-rw-r--r--modern/src/StartPage.js19
-rw-r--r--modern/src/UserPage.js47
-rw-r--r--modern/src/admin/ServerPage.js56
-rw-r--r--modern/src/admin/StatisticsPage.js30
-rw-r--r--modern/src/admin/UsersPage.js74
-rw-r--r--modern/src/attributes/AddAttributeDialog.js36
-rw-r--r--modern/src/attributes/EditAttributesView.js129
-rw-r--r--modern/src/attributes/deviceAttributes.js4
-rw-r--r--modern/src/attributes/geofenceAttributes.js4
-rw-r--r--modern/src/attributes/positionAttributes.js10
-rw-r--r--modern/src/attributes/userAttributes.js12
-rw-r--r--modern/src/common/converter.js24
-rw-r--r--modern/src/common/deviceCategories.js2
-rw-r--r--modern/src/common/formatter.js54
-rw-r--r--modern/src/common/localization.js116
-rw-r--r--modern/src/common/preferences.js30
-rw-r--r--modern/src/common/stringUtils.js8
-rw-r--r--modern/src/components/registration/LoginForm.js71
-rw-r--r--modern/src/components/registration/RegisterForm.js82
-rw-r--r--modern/src/components/registration/ResetPasswordForm.js13
-rw-r--r--modern/src/components/reports/ReportNavbar.js42
-rw-r--r--modern/src/components/reports/ReportSidebar.js18
-rw-r--r--modern/src/form/LinkField.js44
-rw-r--r--modern/src/form/SelectField.js23
-rw-r--r--modern/src/index.js4
-rw-r--r--modern/src/map/AccuracyMap.js36
-rw-r--r--modern/src/map/CurrentLocationMap.js2
-rw-r--r--modern/src/map/CurrentPositionsMap.js6
-rw-r--r--modern/src/map/GeofenceEditMap.js36
-rw-r--r--modern/src/map/GeofenceMap.js56
-rw-r--r--modern/src/map/Map.js33
-rw-r--r--modern/src/map/PositionsMap.js71
-rw-r--r--modern/src/map/ReplayPathMap.js28
-rw-r--r--modern/src/map/SelectedDeviceMap.js4
-rw-r--r--modern/src/map/StatusView.js65
-rw-r--r--modern/src/map/mapStyles.js42
-rw-r--r--modern/src/map/mapUtil.js57
-rw-r--r--modern/src/map/switcher/switcher.js5
-rw-r--r--modern/src/reactHelper.js5
-rw-r--r--modern/src/reports/ChartReportPage.js69
-rw-r--r--modern/src/reports/EventReportPage.js39
-rw-r--r--modern/src/reports/Graph.js37
-rw-r--r--modern/src/reports/ReplayPage.js36
-rw-r--r--modern/src/reports/ReportFilter.js85
-rw-r--r--modern/src/reports/ReportLayoutPage.js45
-rw-r--r--modern/src/reports/RouteReportPage.js24
-rw-r--r--modern/src/reports/StopReportPage.js33
-rw-r--r--modern/src/reports/SummaryReportPage.js38
-rw-r--r--modern/src/reports/TripReportPage.js33
-rw-r--r--modern/src/serviceWorker.js38
-rw-r--r--modern/src/settings/ComputedAttributePage.js60
-rw-r--r--modern/src/settings/ComputedAttributesPage.js73
-rw-r--r--modern/src/settings/DriverPage.js27
-rw-r--r--modern/src/settings/DriversPage.js66
-rw-r--r--modern/src/settings/GroupPage.js27
-rw-r--r--modern/src/settings/GroupsPage.js62
-rw-r--r--modern/src/settings/MaintenancePage.js94
-rw-r--r--modern/src/settings/MaintenancesPage.js78
-rw-r--r--modern/src/settings/NotificationPage.js56
-rw-r--r--modern/src/settings/NotificationsPage.js76
-rw-r--r--modern/src/setupProxy.js8
-rw-r--r--modern/src/store/devices.js8
-rw-r--r--modern/src/store/drivers.js4
-rw-r--r--modern/src/store/geofences.js6
-rw-r--r--modern/src/store/groups.js4
-rw-r--r--modern/src/store/maintenances.js4
-rw-r--r--modern/src/store/positions.js4
-rw-r--r--modern/src/theme/dimensions.js2
-rw-r--r--modern/src/theme/index.js2
-rw-r--r--modern/src/theme/overrides.js50
89 files changed, 1661 insertions, 1484 deletions
diff --git a/modern/.eslintrc.js b/modern/.eslintrc.js
new file mode 100644
index 0000000..a108980
--- /dev/null
+++ b/modern/.eslintrc.js
@@ -0,0 +1,18 @@
+module.exports = {
+ "extends": "airbnb",
+ "plugins": [
+ "react"
+ ],
+ "ignorePatterns": ["serviceWorker.js", "localization.js", "switcher.js"],
+ "rules": {
+ "max-len": [0],
+ "no-shadow": [0],
+ "no-return-assign": [0],
+ "no-param-reassign": [0],
+ "no-prototype-builtins": [0],
+ "react/jsx-filename-extension": [1, { "extensions": [".js"] }],
+ "react/prop-types": [0],
+ "react/jsx-props-no-spreading": [0],
+ "jsx-a11y/anchor-is-valid": [0]
+ }
+};
diff --git a/modern/craco.config.js b/modern/craco.config.js
index 3e5d98e..32971f2 100644
--- a/modern/craco.config.js
+++ b/modern/craco.config.js
@@ -1,12 +1,12 @@
module.exports = {
webpack: {
- configure: webpackConfig => {
+ configure: (webpackConfig) => {
const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
- ({ constructor }) => constructor && constructor.name === 'ModuleScopePlugin'
+ ({ constructor }) => constructor && constructor.name === 'ModuleScopePlugin',
);
webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
return webpackConfig;
- }
- }
+ },
+ },
};
diff --git a/modern/package.json b/modern/package.json
index 6c74cbe..f986b31 100644
--- a/modern/package.json
+++ b/modern/package.json
@@ -10,6 +10,7 @@
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.58",
"@reduxjs/toolkit": "^1.6.0",
+ "@turf/circle": "^6.5.0",
"@turf/turf": "^6.4.0",
"canvas-tint-image": "^2.0.1",
"maplibre-gl": "^1.15.0",
@@ -31,7 +32,9 @@
"start": "craco start",
"build": "craco build",
"build_release": "PUBLIC_URL=/modern/ craco build",
- "test": "craco test"
+ "test": "craco test",
+ "lint": "eslint .",
+ "lint:fix": "eslint --fix --ext .js ."
},
"browserslist": {
"production": [
@@ -44,5 +47,11 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "eslint": "^6.8.0",
+ "eslint-config-airbnb": "^18.2.1",
+ "eslint-plugin-react": "^7.24.0",
+ "eslint-plugin-react-hooks": "^1.7.0"
}
}
diff --git a/modern/src/App.js b/modern/src/App.js
index b76995e..ac7cdb2 100644
--- a/modern/src/App.js
+++ b/modern/src/App.js
@@ -1,7 +1,9 @@
import React from 'react';
import { ThemeProvider } from '@material-ui/core/styles';
-import { Switch, Route } from 'react-router-dom'
+import { Switch, Route } from 'react-router-dom';
import CssBaseline from '@material-ui/core/CssBaseline';
+import { useSelector } from 'react-redux';
+import { LinearProgress } from '@material-ui/core';
import MainPage from './MainPage';
import RouteReportPage from './reports/RouteReportPage';
import ServerPage from './admin/ServerPage';
@@ -16,8 +18,6 @@ import GroupPage from './settings/GroupPage';
import PositionPage from './PositionPage';
import EventReportPage from './reports/EventReportPage';
import ReplayPage from './reports/ReplayPage';
-import { useSelector } from 'react-redux';
-import { LinearProgress } from '@material-ui/core';
import TripReportPage from './reports/TripReportPage';
import StopReportPage from './reports/StopReportPage';
import SummaryReportPage from './reports/SummaryReportPage';
@@ -40,7 +40,7 @@ import GeofencesPage from './GeofencesPage';
import GeofencePage from './GeofencePage';
const App = () => {
- const initialized = useSelector(state => !!state.session.server && !!state.session.user);
+ const initialized = useSelector((state) => !!state.session.server && !!state.session.user);
return (
<ThemeProvider theme={theme}>
@@ -48,44 +48,44 @@ const App = () => {
<SocketController />
<CachingController />
<Switch>
- <Route exact path='/login' component={LoginForm} />
- <Route exact path='/register' component={RegisterForm} />
- <Route exact path='/reset-password' component={ResetPasswordForm} />
+ <Route exact path="/login" component={LoginForm} />
+ <Route exact path="/register" component={RegisterForm} />
+ <Route exact path="/reset-password" component={ResetPasswordForm} />
<Route>
{!initialized ? (<LinearProgress />) : (
<Switch>
- <Route exact path='/' component={MainPage} />
- <Route exact path='/replay' component={ReplayPage} />
- <Route exact path='/position/:id?' component={PositionPage} />
- <Route exact path='/user/:id?' component={UserPage} />
- <Route exact path='/device/:id?' component={DevicePage} />
- <Route exact path='/geofence/:id?' component={GeofencePage} />
- <Route exact path='/geofences' component={GeofencesPage} />
- <Route exact path='/settings/notifications' component={NotificationsPage} />
- <Route exact path='/settings/notification/:id?' component={NotificationPage} />
- <Route exact path='/settings/groups' component={GroupsPage} />
- <Route exact path='/settings/group/:id?' component={GroupPage} />
- <Route exact path='/settings/drivers' component={DriversPage} />
- <Route exact path='/settings/driver/:id?' component={DriverPage} />
- <Route exact path='/settings/attributes' component={ComputedAttributesPage} />
- <Route exact path='/settings/attribute/:id?' component={ComputedAttributePage} />
- <Route exact path='/settings/maintenances' component={MaintenancesPage} />
- <Route exact path='/settings/maintenance/:id?' component={MaintenancePage} />
- <Route exact path='/admin/server' component={ServerPage} />
- <Route exact path='/admin/users' component={UsersPage} />
- <Route exact path='/admin/statistics' component={StatisticsPage} />
- <Route exact path='/reports/route' component={RouteReportPage} />
- <Route exact path='/reports/event' component={EventReportPage} />
- <Route exact path='/reports/trip' component={TripReportPage} />
- <Route exact path='/reports/stop' component={StopReportPage} />
- <Route exact path='/reports/summary' component={SummaryReportPage} />
- <Route exact path='/reports/chart' component={ChartReportPage} />
+ <Route exact path="/" component={MainPage} />
+ <Route exact path="/replay" component={ReplayPage} />
+ <Route exact path="/position/:id?" component={PositionPage} />
+ <Route exact path="/user/:id?" component={UserPage} />
+ <Route exact path="/device/:id?" component={DevicePage} />
+ <Route exact path="/geofence/:id?" component={GeofencePage} />
+ <Route exact path="/geofences" component={GeofencesPage} />
+ <Route exact path="/settings/notifications" component={NotificationsPage} />
+ <Route exact path="/settings/notification/:id?" component={NotificationPage} />
+ <Route exact path="/settings/groups" component={GroupsPage} />
+ <Route exact path="/settings/group/:id?" component={GroupPage} />
+ <Route exact path="/settings/drivers" component={DriversPage} />
+ <Route exact path="/settings/driver/:id?" component={DriverPage} />
+ <Route exact path="/settings/attributes" component={ComputedAttributesPage} />
+ <Route exact path="/settings/attribute/:id?" component={ComputedAttributePage} />
+ <Route exact path="/settings/maintenances" component={MaintenancesPage} />
+ <Route exact path="/settings/maintenance/:id?" component={MaintenancePage} />
+ <Route exact path="/admin/server" component={ServerPage} />
+ <Route exact path="/admin/users" component={UsersPage} />
+ <Route exact path="/admin/statistics" component={StatisticsPage} />
+ <Route exact path="/reports/route" component={RouteReportPage} />
+ <Route exact path="/reports/event" component={EventReportPage} />
+ <Route exact path="/reports/trip" component={TripReportPage} />
+ <Route exact path="/reports/stop" component={StopReportPage} />
+ <Route exact path="/reports/summary" component={SummaryReportPage} />
+ <Route exact path="/reports/chart" component={ChartReportPage} />
</Switch>
)}
</Route>
</Switch>
</ThemeProvider>
);
-}
+};
export default App;
diff --git a/modern/src/CachingController.js b/modern/src/CachingController.js
index 3f808de..d6e2006 100644
--- a/modern/src/CachingController.js
+++ b/modern/src/CachingController.js
@@ -1,10 +1,12 @@
-import { useDispatch, useSelector } from 'react-redux';
-import { connect } from 'react-redux';
-import { geofencesActions, groupsActions, driversActions, maintenancesActions } from './store';
+import { useDispatch, useSelector, connect } from 'react-redux';
+
+import {
+ geofencesActions, groupsActions, driversActions, maintenancesActions,
+} from './store';
import { useEffectAsync } from './reactHelper';
const CachingController = () => {
- const authenticated = useSelector(state => !!state.session.user);
+ const authenticated = useSelector((state) => !!state.session.user);
const dispatch = useDispatch();
useEffectAsync(async () => {
@@ -23,8 +25,8 @@ const CachingController = () => {
dispatch(groupsActions.update(await response.json()));
}
}
- }, [authenticated]);
-
+ }, [authenticated]);
+
useEffectAsync(async () => {
if (authenticated) {
const response = await fetch('/api/drivers');
@@ -33,7 +35,7 @@ const CachingController = () => {
}
}
}, [authenticated]);
-
+
useEffectAsync(async () => {
if (authenticated) {
const response = await fetch('/api/maintenance');
@@ -41,9 +43,9 @@ const CachingController = () => {
dispatch(maintenancesActions.update(await response.json()));
}
}
- }, [authenticated]);
-
+ }, [authenticated]);
+
return null;
-}
+};
export default connect()(CachingController);
diff --git a/modern/src/DevicePage.js b/modern/src/DevicePage.js
index ed5a6cb..699e97c 100644
--- a/modern/src/DevicePage.js
+++ b/modern/src/DevicePage.js
@@ -1,14 +1,16 @@
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t from './common/localization';
import EditItemView from './EditItemView';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox } from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import EditAttributesView from './attributes/EditAttributesView';
import deviceAttributes from './attributes/deviceAttributes';
import SelectField from './form/SelectField';
-import { deviceCategories } from './common/deviceCategories';
+import deviceCategories from './common/deviceCategories';
import LinkField from './form/LinkField';
import { prefixString } from './common/stringUtils';
@@ -25,7 +27,8 @@ const DevicePage = () => {
return (
<EditItemView endpoint="devices" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -37,15 +40,17 @@ const DevicePage = () => {
<TextField
margin="normal"
value={item.name || ''}
- onChange={event => setItem({...item, name: event.target.value})}
+ onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled" />
+ variant="filled"
+ />
<TextField
margin="normal"
value={item.uniqueId || ''}
- onChange={event => setItem({...item, uniqueId: event.target.value})}
+ onChange={(event) => setItem({ ...item, uniqueId: event.target.value })}
label={t('deviceIdentifier')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -58,42 +63,48 @@ const DevicePage = () => {
<SelectField
margin="normal"
value={item.groupId || 0}
- onChange={event => setItem({...item, groupId: Number(event.target.value)})}
+ onChange={(event) => setItem({ ...item, groupId: Number(event.target.value) })}
endpoint="/api/groups"
label={t('groupParent')}
- variant="filled" />
+ variant="filled"
+ />
<TextField
margin="normal"
value={item.phone || ''}
- onChange={event => setItem({...item, phone: event.target.value})}
+ onChange={(event) => setItem({ ...item, phone: event.target.value })}
label={t('sharedPhone')}
- variant="filled" />
+ variant="filled"
+ />
<TextField
margin="normal"
value={item.model || ''}
- onChange={event => setItem({...item, model: event.target.value})}
+ onChange={(event) => setItem({ ...item, model: event.target.value })}
label={t('deviceModel')}
- variant="filled" />
+ variant="filled"
+ />
<TextField
margin="normal"
value={item.contact || ''}
- onChange={event => setItem({...item, contact: event.target.value})}
+ onChange={(event) => setItem({ ...item, contact: event.target.value })}
label={t('deviceContact')}
- variant="filled" />
+ variant="filled"
+ />
<SelectField
margin="normal"
value={item.category || 'default'}
emptyValue={null}
- onChange={event => setItem({...item, category: event.target.value})}
- data={deviceCategories.map(category => ({
+ onChange={(event) => setItem({ ...item, category: event.target.value })}
+ data={deviceCategories.map((category) => ({
id: category,
- name: t(`category${category.replace(/^\w/, c => c.toUpperCase())}`)
+ name: t(`category${category.replace(/^\w/, (c) => c.toUpperCase())}`),
}))}
label={t('deviceCategory')}
- variant="filled" />
+ variant="filled"
+ />
<FormControlLabel
- control={<Checkbox checked={item.disabled} onChange={event => setItem({...item, disabled: event.target.checked})} />}
- label={t('sharedDisabled')} />
+ control={<Checkbox checked={item.disabled} onChange={(event) => setItem({ ...item, disabled: event.target.checked })} />}
+ label={t('sharedDisabled')}
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -105,12 +116,13 @@ const DevicePage = () => {
<AccordionDetails className={classes.details}>
<EditAttributesView
attributes={item.attributes}
- setAttributes={attributes => setItem({...item, attributes})}
+ setAttributes={(attributes) => setItem({ ...item, attributes })}
definitions={deviceAttributes}
- />
+ />
</AccordionDetails>
</Accordion>
- {item.id &&
+ {item.id
+ && (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="subtitle1">
@@ -121,57 +133,62 @@ const DevicePage = () => {
<LinkField
margin="normal"
endpointAll="/api/geofences"
- endpointLinked={"/api/geofences?deviceId=" + item.id}
+ endpointLinked={`/api/geofences?deviceId=${item.id}`}
baseId={item.id}
keyBase="deviceId"
keyLink="geofenceId"
label={t('sharedGeofences')}
- variant="filled" />
+ variant="filled"
+ />
<LinkField
margin="normal"
endpointAll="/api/notifications"
- endpointLinked={"/api/notifications?deviceId=" + item.id}
+ endpointLinked={`/api/notifications?deviceId=${item.id}`}
baseId={item.id}
keyBase="deviceId"
keyLink="notificationId"
- titleGetter={it => t(prefixString('event', it.type))}
+ titleGetter={(it) => t(prefixString('event', it.type))}
label={t('sharedNotifications')}
- variant="filled" />
+ variant="filled"
+ />
<LinkField
margin="normal"
endpointAll="/api/drivers"
- endpointLinked={"/api/drivers?deviceId=" + item.id}
+ endpointLinked={`/api/drivers?deviceId=${item.id}`}
baseId={item.id}
keyBase="deviceId"
keyLink="driverId"
label={t('sharedDrivers')}
- variant="filled" />
+ variant="filled"
+ />
<LinkField
margin="normal"
endpointAll="/api/attributes/computed"
- endpointLinked={"/api/attributes/computed?deviceId=" + item.id}
+ endpointLinked={`/api/attributes/computed?deviceId=${item.id}`}
baseId={item.id}
keyBase="deviceId"
keyLink="attributeId"
- titleGetter={it => it.description}
+ titleGetter={(it) => it.description}
label={t('sharedComputedAttributes')}
- variant="filled" />
+ variant="filled"
+ />
<LinkField
margin="normal"
endpointAll="/api/maintenance"
- endpointLinked={"/api/maintenance?deviceId=" + item.id}
+ endpointLinked={`/api/maintenance?deviceId=${item.id}`}
baseId={item.id}
keyBase="deviceId"
keyLink="maintenanceId"
label={t('sharedMaintenance')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
- }
+ )}
</>
- }
+ )}
</EditItemView>
);
-}
+};
export default DevicePage;
diff --git a/modern/src/DevicesList.js b/modern/src/DevicesList.js
index f66d717..85b936c 100644
--- a/modern/src/DevicesList.js
+++ b/modern/src/DevicesList.js
@@ -34,7 +34,7 @@ const DeviceRow = ({ data, index, style }) => {
const { items, onMenuClick } = data;
const item = items[index];
-
+
return (
<div style={style}>
<Fragment key={index}>
@@ -61,7 +61,7 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => {
const classes = useStyles();
const dispatch = useDispatch();
- const items = useSelector(state => Object.values(state.devices.items));
+ const items = useSelector((state) => Object.values(state.devices.items));
useEffectAsync(async () => {
const response = await fetch('/api/devices');
@@ -79,7 +79,8 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => {
height={height}
itemCount={items.length}
itemData={{ items, onMenuClick }}
- itemSize={72 + 1} >
+ itemSize={72 + 1}
+ >
{DeviceRow}
</FixedSizeList>
</List>
@@ -88,10 +89,8 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => {
);
};
-const DevicesList = () => {
- return (
- <EditCollectionView content={DeviceView} editPath="/device" endpoint="devices" />
- );
-};
+const DevicesList = () => (
+ <EditCollectionView content={DeviceView} editPath="/device" endpoint="devices" />
+);
export default DevicesList;
diff --git a/modern/src/EditCollectionView.js b/modern/src/EditCollectionView.js
index 572a1d1..7d5e4b2 100644
--- a/modern/src/EditCollectionView.js
+++ b/modern/src/EditCollectionView.js
@@ -10,7 +10,7 @@ import { useSelector } from 'react-redux';
import t from './common/localization';
import RemoveDialog from './RemoveDialog';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
fab: {
position: 'absolute',
bottom: theme.spacing(2),
@@ -18,7 +18,9 @@ const useStyles = makeStyles(theme => ({
},
}));
-const EditCollectionView = ({ content, editPath, endpoint, disableAdd }) => {
+const EditCollectionView = ({
+ content, editPath, endpoint, disableAdd,
+}) => {
const classes = useStyles();
const history = useHistory();
@@ -26,47 +28,48 @@ const EditCollectionView = ({ content, editPath, endpoint, disableAdd }) => {
const [selectedAnchorEl, setSelectedAnchorEl] = useState(null);
const [removeDialogShown, setRemoveDialogShown] = useState(false);
const [updateTimestamp, setUpdateTimestamp] = useState(Date.now());
- const adminEnabled = useSelector(state => state.session.user && state.session.user.administrator);
+ const adminEnabled = useSelector((state) => state.session.user && state.session.user.administrator);
const menuShow = (anchorId, itemId) => {
setSelectedAnchorEl(anchorId);
setSelectedId(itemId);
- }
+ };
const menuHide = () => {
setSelectedAnchorEl(null);
- }
+ };
const handleAdd = () => {
history.push(editPath);
menuHide();
- }
+ };
const handleEdit = () => {
history.push(`${editPath}/${selectedId}`);
menuHide();
- }
+ };
const handleRemove = () => {
setRemoveDialogShown(true);
menuHide();
- }
+ };
const handleRemoveResult = () => {
setRemoveDialogShown(false);
setUpdateTimestamp(Date.now());
- }
+ };
const Content = content;
return (
<>
<Content updateTimestamp={updateTimestamp} onMenuClick={menuShow} />
- {adminEnabled && !disableAdd &&
+ {adminEnabled && !disableAdd
+ && (
<Fab size="medium" color="primary" className={classes.fab} onClick={handleAdd}>
<AddIcon />
</Fab>
- }
+ )}
<Menu open={!!selectedAnchorEl} anchorEl={selectedAnchorEl} onClose={menuHide}>
<MenuItem onClick={handleEdit}>{t('sharedEdit')}</MenuItem>
<MenuItem onClick={handleRemove}>{t('sharedRemove')}</MenuItem>
@@ -74,6 +77,6 @@ const EditCollectionView = ({ content, editPath, endpoint, disableAdd }) => {
<RemoveDialog open={removeDialogShown} endpoint={endpoint} itemId={selectedId} onResult={handleRemoveResult} />
</>
);
-}
+};
export default EditCollectionView;
diff --git a/modern/src/EditItemView.js b/modern/src/EditItemView.js
index 16fbbae..9bf91a6 100644
--- a/modern/src/EditItemView.js
+++ b/modern/src/EditItemView.js
@@ -1,15 +1,15 @@
import React from 'react';
-import MainToolbar from './MainToolbar';
import { useHistory, useParams } from 'react-router-dom';
import { makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import Button from '@material-ui/core/Button';
import FormControl from '@material-ui/core/FormControl';
+import MainToolbar from './MainToolbar';
import t from './common/localization';
import { useEffectAsync } from './reactHelper';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
container: {
marginTop: theme.spacing(2),
},
@@ -22,7 +22,9 @@ const useStyles = makeStyles(theme => ({
},
}));
-const EditItemView = ({ children, endpoint, item, setItem }) => {
+const EditItemView = ({
+ children, endpoint, item, setItem,
+}) => {
const history = useHistory();
const classes = useStyles();
const { id } = useParams();
@@ -58,14 +60,14 @@ const EditItemView = ({ children, endpoint, item, setItem }) => {
return (
<>
<MainToolbar />
- <Container maxWidth='xs' className={classes.container}>
+ <Container maxWidth="xs" className={classes.container}>
{children}
- <FormControl fullWidth margin='normal'>
+ <FormControl fullWidth margin="normal">
<div className={classes.buttons}>
- <Button type='button' color='primary' variant='outlined' onClick={() => history.goBack()}>
+ <Button type="button" color="primary" variant="outlined" onClick={() => history.goBack()}>
{t('sharedCancel')}
</Button>
- <Button type='button' color='primary' variant='contained' onClick={handleSave}>
+ <Button type="button" color="primary" variant="contained" onClick={handleSave}>
{t('sharedSave')}
</Button>
</div>
@@ -73,6 +75,6 @@ const EditItemView = ({ children, endpoint, item, setItem }) => {
</Container>
</>
);
-}
+};
export default EditItemView;
diff --git a/modern/src/GeofencePage.js b/modern/src/GeofencePage.js
index 6c5db9b..06456fc 100644
--- a/modern/src/GeofencePage.js
+++ b/modern/src/GeofencePage.js
@@ -1,10 +1,12 @@
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t from './common/localization';
import EditItemView from './EditItemView';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import EditAttributesView from './attributes/EditAttributesView';
import geofenceAttributes from './attributes/geofenceAttributes';
@@ -21,7 +23,8 @@ const GeofencePage = () => {
return (
<EditItemView endpoint="geofences" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -33,9 +36,10 @@ const GeofencePage = () => {
<TextField
margin="normal"
value={item.name || ''}
- onChange={event => setItem({...item, name: event.target.value})}
+ onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -47,15 +51,15 @@ const GeofencePage = () => {
<AccordionDetails className={classes.details}>
<EditAttributesView
attributes={item.attributes}
- setAttributes={attributes => setItem({...item, attributes})}
+ setAttributes={(attributes) => setItem({ ...item, attributes })}
definitions={geofenceAttributes}
- />
+ />
</AccordionDetails>
</Accordion>
</>
- }
+ )}
</EditItemView>
);
-}
+};
export default GeofencePage;
diff --git a/modern/src/GeofencesList.js b/modern/src/GeofencesList.js
index 2988bef..572ac5b 100644
--- a/modern/src/GeofencesList.js
+++ b/modern/src/GeofencesList.js
@@ -28,7 +28,7 @@ const GeofenceView = ({ onMenuClick }) => {
const classes = useStyles();
const dispatch = useDispatch();
- const items = useSelector(state => Object.values(state.geofences.items));
+ const items = useSelector((state) => Object.values(state.geofences.items));
return (
<List className={classes.list}>
@@ -47,12 +47,10 @@ const GeofenceView = ({ onMenuClick }) => {
))}
</List>
);
-}
+};
-const GeofencesList = () => {
- return (
- <EditCollectionView content={GeofenceView} editPath="/geofence" endpoint="geofences" disableAdd />
- );
-}
+const GeofencesList = () => (
+ <EditCollectionView content={GeofenceView} editPath="/geofence" endpoint="geofences" disableAdd />
+);
export default GeofencesList;
diff --git a/modern/src/GeofencesPage.js b/modern/src/GeofencesPage.js
index 389ac99..95c7151 100644
--- a/modern/src/GeofencesPage.js
+++ b/modern/src/GeofencesPage.js
@@ -8,7 +8,7 @@ import CurrentLocationMap from './map/CurrentLocationMap';
import GeofenceEditMap from './map/GeofenceEditMap';
import GeofencesList from './GeofencesList';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
height: '100%',
display: 'flex',
@@ -21,7 +21,7 @@ const useStyles = makeStyles(theme => ({
flexDirection: 'row',
[theme.breakpoints.down('xs')]: {
flexDirection: 'column-reverse',
- }
+ },
},
drawerPaper: {
position: 'relative',
@@ -30,7 +30,7 @@ const useStyles = makeStyles(theme => ({
},
[theme.breakpoints.down('xs')]: {
height: 250,
- }
+ },
},
mapContainer: {
flexGrow: 1,
@@ -46,8 +46,9 @@ const GeofencesPage = ({ width }) => {
<div className={classes.content}>
<Drawer
anchor={isWidthUp('sm', width) ? 'left' : 'bottom'}
- variant='permanent'
- classes={{ paper: classes.drawerPaper }}>
+ variant="permanent"
+ classes={{ paper: classes.drawerPaper }}
+ >
<GeofencesList />
</Drawer>
<div className={classes.mapContainer}>
@@ -61,6 +62,6 @@ const GeofencesPage = ({ width }) => {
</div>
</div>
);
-}
+};
export default withWidth()(GeofencesPage);
diff --git a/modern/src/Logo.js b/modern/src/Logo.js
index bea14d8..1fb1ac8 100644
--- a/modern/src/Logo.js
+++ b/modern/src/Logo.js
@@ -1,31 +1,28 @@
import React from 'react';
-const Logo = ({ fill }) => {
-
- return (
- <svg xmlns='http://www.w3.org/2000/svg' height="64" viewBox="0 0 240 64" width="240" version="1.1">
- <g id="layer1">
- <rect id="rect3778" height="64" width="236.1" y="0" x="0" fill="none"/>
- <ellipse id="path3038" rx="28.995" ry="28.995" transform="rotate(-30)" cy="43.713" cx="11.713" stroke-width="10.699" fill="#fff"/>
- <g fill= {fill}>
- <circle id="path2993" strokeWidth="1.3262" transform="rotate(-30)" cy="43.713" cx="9.4364" r="2.2765"/>
- <path id="path3004" d="m37.012 24.177-2.8428 3.6128c0.66345 0.52205 1.3255 1.1576 1.7734 1.9333 0.4479 0.77578 0.66726 1.6669 0.78764 2.5025l4.5502-0.65558c-0.193-1.42-0.633-2.804-1.394-4.123s-1.74-2.391-2.874-3.27z" strokeWidth="1.0095"/>
- <path id="path3014" d="m42.504 16.9-2.8428 3.6128c1.607 1.2355 3.0914 2.7935 4.1679 4.6581s1.6835 3.9291 1.95 5.9386l4.5502-0.65558c-0.33967-2.5954-1.1669-5.1513-2.5573-7.5594-1.3903-2.4081-3.1901-4.4025-5.268-5.9944z" strokeWidth="1.0095"/>
- <path id="path3036" d="m2.607 52.819a9.1058 9.1058 0 0 1 -7.8859 -4.5529 9.1058 9.1058 0 0 1 0 -9.1058 9.1058 9.1058 0 0 1 7.8859 -4.5529l-2e-7 9.1058z" transform="rotate(-30)" strokeWidth="3.6204"/>
- <path id="path3038-8" d="m17.502 6.8895c-13.868 8.0065-18.619 25.74-10.612 39.608 8.006 13.868 25.739 18.619 39.608 10.613 13.868-8.007 18.619-25.74 10.613-39.609-8.007-13.868-25.74-18.619-39.609-10.612zm1.706 2.9541c12.237-7.0648 27.884-2.8722 34.948 9.3644 7.065 12.237 2.873 27.884-9.364 34.948-12.237 7.065-27.884 2.873-34.948-9.364-7.0652-12.237-2.8726-27.884 9.364-34.948z" strokeWidth="1.0095"/>
+const Logo = ({ fill }) => (
+ <svg xmlns="http://www.w3.org/2000/svg" height="64" viewBox="0 0 240 64" width="240" version="1.1">
+ <g id="layer1">
+ <rect id="rect3778" height="64" width="236.1" y="0" x="0" fill="none" />
+ <ellipse id="path3038" rx="28.995" ry="28.995" transform="rotate(-30)" cy="43.713" cx="11.713" strokeWidth="10.699" fill="#fff" />
+ <g fill={fill}>
+ <circle id="path2993" strokeWidth="1.3262" transform="rotate(-30)" cy="43.713" cx="9.4364" r="2.2765" />
+ <path id="path3004" d="m37.012 24.177-2.8428 3.6128c0.66345 0.52205 1.3255 1.1576 1.7734 1.9333 0.4479 0.77578 0.66726 1.6669 0.78764 2.5025l4.5502-0.65558c-0.193-1.42-0.633-2.804-1.394-4.123s-1.74-2.391-2.874-3.27z" strokeWidth="1.0095" />
+ <path id="path3014" d="m42.504 16.9-2.8428 3.6128c1.607 1.2355 3.0914 2.7935 4.1679 4.6581s1.6835 3.9291 1.95 5.9386l4.5502-0.65558c-0.33967-2.5954-1.1669-5.1513-2.5573-7.5594-1.3903-2.4081-3.1901-4.4025-5.268-5.9944z" strokeWidth="1.0095" />
+ <path id="path3036" d="m2.607 52.819a9.1058 9.1058 0 0 1 -7.8859 -4.5529 9.1058 9.1058 0 0 1 0 -9.1058 9.1058 9.1058 0 0 1 7.8859 -4.5529l-2e-7 9.1058z" transform="rotate(-30)" strokeWidth="3.6204" />
+ <path id="path3038-8" d="m17.502 6.8895c-13.868 8.0065-18.619 25.74-10.612 39.608 8.006 13.868 25.739 18.619 39.608 10.613 13.868-8.007 18.619-25.74 10.613-39.609-8.007-13.868-25.74-18.619-39.609-10.612zm1.706 2.9541c12.237-7.0648 27.884-2.8722 34.948 9.3644 7.065 12.237 2.873 27.884-9.364 34.948-12.237 7.065-27.884 2.873-34.948-9.364-7.0652-12.237-2.8726-27.884 9.364-34.948z" strokeWidth="1.0095" />
<g id="text3003" ariaLabel="Traccar">
- <path id="path4172" d="m89.719 48.671h-3.915v-30.192h-10.663v-3.4775h25.241v3.4775h-10.663v30.192z"/>
- <path id="path4174" d="m116.36 22.969q1.6812 0 3.0169 0.27636l-0.52968 3.5466q-1.566-0.34544-2.7636-0.34544-3.063 0-5.2508 2.4872-2.1648 2.4872-2.1648 6.195v13.541h-3.8229v-25.241h3.1551l0.43756 4.675h0.18424q1.4048-2.4642 3.3854-3.7999t4.3526-1.3357z"/>
- <path id="path4176" d="m139.62 48.671-0.75998-3.5926h-0.18424q-1.8884 2.3721-3.7769 3.2242-1.8654 0.82907-4.675 0.82907-3.7538 0-5.8956-1.9345-2.1187-1.9345-2.1187-5.5041 0-7.6459 12.229-8.0143l4.2835-0.13818v-1.566q0-2.9708-1.2897-4.3756-1.2666-1.4278-4.0763-1.4278-3.1551 0-7.1392 1.9345l-1.1745-2.9248q1.8654-1.0133 4.0762-1.589 2.2339-0.57574 4.4678-0.57574 4.5138 0 6.6786 2.0036 2.1878 2.0036 2.1878 6.4253v17.226h-2.8326zm-8.6361-2.6945q3.5696 0 5.5962-1.9575 2.0496-1.9575 2.0496-5.4811v-2.2799l-3.8229 0.16121q-4.5599 0.16121-6.5865 1.4278-2.0036 1.2436-2.0036 3.892 0 2.0727 1.2436 3.1551 1.2666 1.0824 3.5236 1.0824z"/>
- <path id="path4178" d="m160.44 49.131q-5.4811 0-8.498-3.3623-2.9939-3.3854-2.9939-9.5573 0-6.3332 3.0399-9.7876 3.063-3.4545 8.7052-3.4545 1.8194 0 3.6387 0.3915t2.8557 0.92119l-1.1745 3.2472q-1.2666-0.50665-2.7636-0.82907-1.4969-0.34544-2.6484-0.34544-7.6919 0-7.6919 9.8106 0 4.652 1.8654 7.1392 1.8884 2.4872 5.5732 2.4872 3.1551 0 6.4713-1.3588v3.3854q-2.5333 1.3127-6.3792 1.3127z"/>
- <path id="path4180" d="m182.92 49.131q-5.4811 0-8.498-3.3623-2.9939-3.3854-2.9939-9.5573 0-6.3332 3.0399-9.7876 3.063-3.4545 8.7052-3.4545 1.8193 0 3.6387 0.3915t2.8557 0.92119l-1.1745 3.2472q-1.2666-0.50665-2.7636-0.82907-1.4969-0.34544-2.6484-0.34544-7.6919 0-7.6919 9.8106 0 4.652 1.8654 7.1392 1.8884 2.4872 5.5732 2.4872 3.1551 0 6.4714-1.3588v3.3854q-2.5333 1.3127-6.3792 1.3127z"/>
- <path id="path4182" d="m210.83 48.671-0.75998-3.5926h-0.18424q-1.8884 2.3721-3.7769 3.2242-1.8654 0.82907-4.675 0.82907-3.7538 0-5.8956-1.9345-2.1187-1.9345-2.1187-5.5041 0-7.6459 12.229-8.0143l4.2835-0.13818v-1.566q0-2.9708-1.2897-4.3756-1.2666-1.4278-4.0762-1.4278-3.1551 0-7.1392 1.9345l-1.1745-2.9248q1.8654-1.0133 4.0762-1.589 2.2339-0.57574 4.4678-0.57574 4.5138 0 6.6786 2.0036 2.1878 2.0036 2.1878 6.4253v17.226h-2.8326zm-8.6361-2.6945q3.5696 0 5.5962-1.9575 2.0496-1.9575 2.0496-5.4811v-2.2799l-3.8229 0.16121q-4.5599 0.16121-6.5865 1.4278-2.0036 1.2436-2.0036 3.892 0 2.0727 1.2436 3.1551 1.2666 1.0824 3.5235 1.0824z"/>
- <path id="path4184" d="m233.08 22.969q1.6812 0 3.0169 0.27636l-0.52968 3.5466q-1.566-0.34544-2.7636-0.34544-3.0629 0-5.2508 2.4872-2.1648 2.4872-2.1648 6.195v13.541h-3.8229v-25.241h3.1551l0.43757 4.675h0.18423q1.4048-2.4642 3.3854-3.7999t4.3526-1.3357z"/>
- </g>
+ <path id="path4172" d="m89.719 48.671h-3.915v-30.192h-10.663v-3.4775h25.241v3.4775h-10.663v30.192z" />
+ <path id="path4174" d="m116.36 22.969q1.6812 0 3.0169 0.27636l-0.52968 3.5466q-1.566-0.34544-2.7636-0.34544-3.063 0-5.2508 2.4872-2.1648 2.4872-2.1648 6.195v13.541h-3.8229v-25.241h3.1551l0.43756 4.675h0.18424q1.4048-2.4642 3.3854-3.7999t4.3526-1.3357z" />
+ <path id="path4176" d="m139.62 48.671-0.75998-3.5926h-0.18424q-1.8884 2.3721-3.7769 3.2242-1.8654 0.82907-4.675 0.82907-3.7538 0-5.8956-1.9345-2.1187-1.9345-2.1187-5.5041 0-7.6459 12.229-8.0143l4.2835-0.13818v-1.566q0-2.9708-1.2897-4.3756-1.2666-1.4278-4.0763-1.4278-3.1551 0-7.1392 1.9345l-1.1745-2.9248q1.8654-1.0133 4.0762-1.589 2.2339-0.57574 4.4678-0.57574 4.5138 0 6.6786 2.0036 2.1878 2.0036 2.1878 6.4253v17.226h-2.8326zm-8.6361-2.6945q3.5696 0 5.5962-1.9575 2.0496-1.9575 2.0496-5.4811v-2.2799l-3.8229 0.16121q-4.5599 0.16121-6.5865 1.4278-2.0036 1.2436-2.0036 3.892 0 2.0727 1.2436 3.1551 1.2666 1.0824 3.5236 1.0824z" />
+ <path id="path4178" d="m160.44 49.131q-5.4811 0-8.498-3.3623-2.9939-3.3854-2.9939-9.5573 0-6.3332 3.0399-9.7876 3.063-3.4545 8.7052-3.4545 1.8194 0 3.6387 0.3915t2.8557 0.92119l-1.1745 3.2472q-1.2666-0.50665-2.7636-0.82907-1.4969-0.34544-2.6484-0.34544-7.6919 0-7.6919 9.8106 0 4.652 1.8654 7.1392 1.8884 2.4872 5.5732 2.4872 3.1551 0 6.4713-1.3588v3.3854q-2.5333 1.3127-6.3792 1.3127z" />
+ <path id="path4180" d="m182.92 49.131q-5.4811 0-8.498-3.3623-2.9939-3.3854-2.9939-9.5573 0-6.3332 3.0399-9.7876 3.063-3.4545 8.7052-3.4545 1.8193 0 3.6387 0.3915t2.8557 0.92119l-1.1745 3.2472q-1.2666-0.50665-2.7636-0.82907-1.4969-0.34544-2.6484-0.34544-7.6919 0-7.6919 9.8106 0 4.652 1.8654 7.1392 1.8884 2.4872 5.5732 2.4872 3.1551 0 6.4714-1.3588v3.3854q-2.5333 1.3127-6.3792 1.3127z" />
+ <path id="path4182" d="m210.83 48.671-0.75998-3.5926h-0.18424q-1.8884 2.3721-3.7769 3.2242-1.8654 0.82907-4.675 0.82907-3.7538 0-5.8956-1.9345-2.1187-1.9345-2.1187-5.5041 0-7.6459 12.229-8.0143l4.2835-0.13818v-1.566q0-2.9708-1.2897-4.3756-1.2666-1.4278-4.0762-1.4278-3.1551 0-7.1392 1.9345l-1.1745-2.9248q1.8654-1.0133 4.0762-1.589 2.2339-0.57574 4.4678-0.57574 4.5138 0 6.6786 2.0036 2.1878 2.0036 2.1878 6.4253v17.226h-2.8326zm-8.6361-2.6945q3.5696 0 5.5962-1.9575 2.0496-1.9575 2.0496-5.4811v-2.2799l-3.8229 0.16121q-4.5599 0.16121-6.5865 1.4278-2.0036 1.2436-2.0036 3.892 0 2.0727 1.2436 3.1551 1.2666 1.0824 3.5235 1.0824z" />
+ <path id="path4184" d="m233.08 22.969q1.6812 0 3.0169 0.27636l-0.52968 3.5466q-1.566-0.34544-2.7636-0.34544-3.0629 0-5.2508 2.4872-2.1648 2.4872-2.1648 6.195v13.541h-3.8229v-25.241h3.1551l0.43757 4.675h0.18423q1.4048-2.4642 3.3854-3.7999t4.3526-1.3357z" />
</g>
- </g>
- </svg>
- )
-}
+ </g>
+ </g>
+ </svg>
+);
export default Logo;
diff --git a/modern/src/MainPage.js b/modern/src/MainPage.js
index 8d0b18d..88608df 100644
--- a/modern/src/MainPage.js
+++ b/modern/src/MainPage.js
@@ -11,7 +11,7 @@ import GeofenceMap from './map/GeofenceMap';
import CurrentPositionsMap from './map/CurrentPositionsMap';
import CurrentLocationMap from './map/CurrentLocationMap';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
height: '100%',
display: 'flex',
@@ -24,7 +24,7 @@ const useStyles = makeStyles(theme => ({
flexDirection: 'row',
[theme.breakpoints.down('xs')]: {
flexDirection: 'column-reverse',
- }
+ },
},
drawerPaper: {
position: 'relative',
@@ -50,8 +50,9 @@ const MainPage = ({ width }) => {
<div className={classes.content}>
<Drawer
anchor={isWidthUp('sm', width) ? 'left' : 'bottom'}
- variant='permanent'
- classes={{ paper: classes.drawerPaper }}>
+ variant="permanent"
+ classes={{ paper: classes.drawerPaper }}
+ >
<DevicesList />
</Drawer>
<div className={classes.mapContainer}>
@@ -68,6 +69,6 @@ const MainPage = ({ width }) => {
</div>
</div>
);
-}
+};
export default withWidth()(MainPage);
diff --git a/modern/src/MainToolbar.js b/modern/src/MainToolbar.js
index 064507f..da7c42c 100644
--- a/modern/src/MainToolbar.js
+++ b/modern/src/MainToolbar.js
@@ -2,7 +2,6 @@ import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { makeStyles } from '@material-ui/core/styles';
import { useDispatch, useSelector } from 'react-redux';
-import { sessionActions } from './store';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
@@ -27,17 +26,18 @@ import FolderIcon from '@material-ui/icons/Folder';
import CreateIcon from '@material-ui/icons/Create';
import ReplayIcon from '@material-ui/icons/Replay';
import BuildIcon from '@material-ui/icons/Build';
+import { sessionActions } from './store';
import t from './common/localization';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
flex: {
- flexGrow: 1
+ flexGrow: 1,
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
},
list: {
- width: 250
+ width: 250,
},
menuButton: {
marginLeft: -12,
@@ -50,11 +50,11 @@ const MainToolbar = () => {
const [drawer, setDrawer] = useState(false);
const classes = useStyles();
const history = useHistory();
- const adminEnabled = useSelector(state => state.session.user && state.session.user.administrator);
- const userId = useSelector(state => state.session.user && state.session.user.id);
+ const adminEnabled = useSelector((state) => state.session.user && state.session.user.administrator);
+ const userId = useSelector((state) => state.session.user && state.session.user.id);
- const openDrawer = () => { setDrawer(true) }
- const closeDrawer = () => { setDrawer(false) }
+ const openDrawer = () => { setDrawer(true); };
+ const closeDrawer = () => { setDrawer(false); };
const handleLogout = async () => {
const response = await fetch('/api/session', { method: 'DELETE' });
@@ -62,7 +62,7 @@ const MainToolbar = () => {
dispatch(sessionActions.updateUser(null));
history.push('/login');
}
- }
+ };
return (
<>
@@ -71,7 +71,8 @@ const MainToolbar = () => {
<IconButton
className={classes.menuButton}
color="inherit"
- onClick={openDrawer}>
+ onClick={openDrawer}
+ >
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit" className={classes.flex}>
@@ -86,7 +87,8 @@ const MainToolbar = () => {
className={classes.list}
role="button"
onClick={closeDrawer}
- onKeyDown={closeDrawer}>
+ onKeyDown={closeDrawer}
+ >
<List>
<ListItem button onClick={() => history.push('/')}>
<ListItemIcon>
@@ -105,15 +107,16 @@ const MainToolbar = () => {
<DescriptionIcon />
</ListItemIcon>
<ListItemText primary={t('reportTitle')} />
- </ListItem>
+ </ListItem>
</List>
<Divider />
<List
- subheader={
+ subheader={(
<ListSubheader>
{t('settingsTitle')}
</ListSubheader>
- }>
+ )}
+ >
<ListItem button disabled={!userId} onClick={() => history.push(`/user/${userId}`)}>
<ListItemIcon>
<PersonIcon />
@@ -161,11 +164,12 @@ const MainToolbar = () => {
<>
<Divider />
<List
- subheader={
+ subheader={(
<ListSubheader>
{t('userAdmin')}
</ListSubheader>
- }>
+ )}
+ >
<ListItem button onClick={() => history.push('/admin/server')}>
<ListItemIcon>
<StorageIcon />
@@ -191,6 +195,6 @@ const MainToolbar = () => {
</Drawer>
</>
);
-}
+};
export default MainToolbar;
diff --git a/modern/src/PositionPage.js b/modern/src/PositionPage.js
index a91a7a1..ce4c4ac 100644
--- a/modern/src/PositionPage.js
+++ b/modern/src/PositionPage.js
@@ -1,14 +1,16 @@
import React, { Fragment, useState } from 'react';
-import t from './common/localization';
-import { makeStyles, Typography, ListItem, ListItemText, ListItemSecondaryAction, List, Container, Paper, Divider } from '@material-ui/core';
+import {
+ makeStyles, Typography, ListItem, ListItemText, ListItemSecondaryAction, List, Container, Paper, Divider,
+} from '@material-ui/core';
import { useParams } from 'react-router-dom';
+import t from './common/localization';
import { useEffectAsync } from './reactHelper';
import MainToolbar from './MainToolbar';
import { formatPosition } from './common/formatter';
import { prefixString } from './common/stringUtils';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
@@ -26,7 +28,7 @@ const PositionPage = () => {
if (id) {
const response = await fetch(`/api/positions?id=${id}`, {
headers: {
- 'Accept': 'application/json'
+ Accept: 'application/json',
},
});
if (response.ok) {
@@ -38,28 +40,27 @@ const PositionPage = () => {
}
}, [id]);
- const formatKey = (key) => {
- return t(prefixString('position', key)) || `${t('sharedAttribute')} "${key}"`;
- };
+ const formatKey = (key) => t(prefixString('position', key)) || `${t('sharedAttribute')} "${key}"`;
const attributesList = () => {
- const combinedList = {...item, ...item.attributes};
- return Object.entries(combinedList).filter(([_, value]) => typeof value !== 'object');
- }
+ const combinedList = { ...item, ...item.attributes };
+ return Object.entries(combinedList).filter(([, value]) => typeof value !== 'object');
+ };
return (
<>
<MainToolbar />
- <Container maxWidth='sm' className={classes.root}>
+ <Container maxWidth="sm" className={classes.root}>
<Paper>
- {item &&
+ {item
+ && (
<List>
{attributesList().map(([key, value], index, list) => (
<Fragment key={key}>
<ListItem>
<ListItemText
primary={formatKey(key)}
- />
+ />
<ListItemSecondaryAction>
<Typography variant="body2">
{formatPosition(value, key)}
@@ -70,11 +71,11 @@ const PositionPage = () => {
</Fragment>
))}
</List>
- }
+ )}
</Paper>
</Container>
</>
);
-}
+};
export default PositionPage;
diff --git a/modern/src/RegisterDialog.js b/modern/src/RegisterDialog.js
index c640c51..aafec66 100644
--- a/modern/src/RegisterDialog.js
+++ b/modern/src/RegisterDialog.js
@@ -1,4 +1,3 @@
-import t from './common/localization'
import React, { useState } from 'react';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
@@ -7,6 +6,7 @@ import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import TextField from '@material-ui/core/TextField';
import Snackbar from '@material-ui/core/Snackbar';
+import t from './common/localization';
const RegisterDialog = ({ showDialog, onResult }) => {
const [name, setName] = useState('');
@@ -14,81 +14,81 @@ const RegisterDialog = ({ showDialog, onResult }) => {
const [password, setPassword] = useState('');
const [snackbarOpen, setSnackbarOpen] = useState(false);
- const submitDisabled = () => {
- return !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password;
- }
+ const submitDisabled = () => !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password;
const handleRegister = async () => {
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({name, email, password})
+ body: JSON.stringify({ name, email, password }),
});
if (response.ok) {
showDialog = false;
setSnackbarOpen(true);
- }
- }
+ }
+ };
if (snackbarOpen) {
-
return (
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
open={snackbarOpen}
autoHideDuration={6000}
- onClose={() => { onResult(true) }}
- message={t('loginCreated')} />
+ onClose={() => { onResult(true); }}
+ message={t('loginCreated')}
+ />
);
-
- } else if (showDialog) {
-
+ } if (showDialog) {
return (
<Dialog
- open={true}
- onClose={() => { onResult(false) }}>
+ open
+ onClose={() => { onResult(false); }}
+ >
<DialogContent>
<DialogContentText>{t('loginRegister')}</DialogContentText>
<TextField
- margin='normal'
+ margin="normal"
required
fullWidth
label={t('sharedName')}
- name='name'
+ name="name"
value={name || ''}
- autoComplete='name'
+ autoComplete="name"
autoFocus
- onChange={event => setName(event.target.value)} />
+ onChange={(event) => setName(event.target.value)}
+ />
<TextField
- margin='normal'
+ margin="normal"
required
fullWidth
- type='email'
+ type="email"
label={t('userEmail')}
- name='email'
+ name="email"
value={email || ''}
- autoComplete='email'
- onChange={event => setEmail(event.target.value)} />
+ autoComplete="email"
+ onChange={(event) => setEmail(event.target.value)}
+ />
<TextField
- margin='normal'
+ margin="normal"
required
fullWidth
label={t('userPassword')}
- name='password'
+ name="password"
value={password || ''}
- type='password'
- autoComplete='current-password'
- onChange={event => setPassword(event.target.value)} />
+ type="password"
+ autoComplete="current-password"
+ onChange={(event) => setPassword(event.target.value)}
+ />
</DialogContent>
<DialogActions>
<Button color="primary" onClick={handleRegister} disabled={submitDisabled()}>{t('loginRegister')}</Button>
<Button autoFocus onClick={() => onResult(false)}>{t('sharedCancel')}</Button>
</DialogActions>
</Dialog>
- )
-
+ );
}
+ return null;
};
export default RegisterDialog;
diff --git a/modern/src/RemoveDialog.js b/modern/src/RemoveDialog.js
index bbcfb22..8ff162c 100644
--- a/modern/src/RemoveDialog.js
+++ b/modern/src/RemoveDialog.js
@@ -1,12 +1,14 @@
-import t from './common/localization'
import React from 'react';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
+import t from './common/localization';
-const RemoveDialog = ({ open, endpoint, itemId, onResult }) => {
+const RemoveDialog = ({
+ open, endpoint, itemId, onResult,
+}) => {
const handleRemove = async () => {
const response = await fetch(`/api/${endpoint}/${itemId}`, { method: 'DELETE' });
if (response.ok) {
@@ -17,7 +19,8 @@ const RemoveDialog = ({ open, endpoint, itemId, onResult }) => {
return (
<Dialog
open={open}
- onClose={() => { onResult(false) }}>
+ onClose={() => { onResult(false); }}
+ >
<DialogContent>
<DialogContentText>{t('sharedRemoveConfirm')}</DialogContentText>
</DialogContent>
diff --git a/modern/src/SocketController.js b/modern/src/SocketController.js
index cda693a..ae82d13 100644
--- a/modern/src/SocketController.js
+++ b/modern/src/SocketController.js
@@ -1,19 +1,19 @@
-import { useDispatch, useSelector } from 'react-redux';
-import { connect } from 'react-redux';
-import { positionsActions, devicesActions, sessionActions } from './store';
+import { useDispatch, useSelector, connect } from 'react-redux';
+
import { useHistory } from 'react-router-dom';
+import { positionsActions, devicesActions, sessionActions } from './store';
import { useEffectAsync } from './reactHelper';
-const displayNotifications = events => {
- if ("Notification" in window) {
- if (Notification.permission === "granted") {
- for (const event of events) {
+const displayNotifications = (events) => {
+ if ('Notification' in window) {
+ if (Notification.permission === 'granted') {
+ events.forEach((event) => {
const notification = new Notification(`Event: ${event.type}`);
setTimeout(notification.close.bind(notification), 4 * 1000);
- }
- } else if (Notification.permission !== "denied") {
- Notification.requestPermission(permission => {
- if (permission === "granted") {
+ });
+ } else if (Notification.permission !== 'denied') {
+ Notification.requestPermission((permission) => {
+ if (permission === 'granted') {
displayNotifications(events);
}
});
@@ -24,11 +24,11 @@ const displayNotifications = events => {
const SocketController = () => {
const dispatch = useDispatch();
const history = useHistory();
- const authenticated = useSelector(state => !!state.session.user);
+ const authenticated = useSelector((state) => !!state.session.user);
const connectSocket = () => {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
- const socket = new WebSocket(protocol + '//' + window.location.host + '/api/socket');
+ const socket = new WebSocket(`${protocol}//${window.location.host}/api/socket`);
socket.onclose = () => {
setTimeout(() => connectSocket(), 60 * 1000);
@@ -46,7 +46,7 @@ const SocketController = () => {
displayNotifications(data.events);
}
};
- }
+ };
useEffectAsync(async () => {
const response = await fetch('/api/server');
@@ -73,6 +73,6 @@ const SocketController = () => {
}, [authenticated]);
return null;
-}
+};
export default connect()(SocketController);
diff --git a/modern/src/StartPage.js b/modern/src/StartPage.js
index 0a08617..3edc5b3 100644
--- a/modern/src/StartPage.js
+++ b/modern/src/StartPage.js
@@ -2,7 +2,7 @@ import React from 'react';
import { useMediaQuery, makeStyles, Paper } from '@material-ui/core';
import { useTheme } from '@material-ui/core/styles';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
height: '100vh',
@@ -23,20 +23,20 @@ const useStyles = makeStyles(theme => ({
},
},
paper: {
- display:'flex',
+ display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
flex: 1,
boxShadow: '-2px 0px 16px rgba(0, 0, 0, 0.25)',
[theme.breakpoints.up('lg')]: {
- padding: theme.spacing(0, 25, 0, 0)
+ padding: theme.spacing(0, 25, 0, 0),
},
},
form: {
maxWidth: theme.spacing(52),
padding: theme.spacing(5),
- width: "100%",
+ width: '100%',
},
}));
@@ -47,11 +47,12 @@ const StartPage = ({ children }) => {
return (
<main className={classes.root}>
<div className={classes.sidebar}>
- {!useMediaQuery(theme.breakpoints.down('md')) &&
+ {!useMediaQuery(theme.breakpoints.down('md'))
+ && (
<svg height="64" width="240">
- <use xlinkHref="/logo.svg#img"></use>
+ <use xlinkHref="/logo.svg#img" />
</svg>
- }
+ )}
</div>
<Paper className={classes.paper}>
<form className={classes.form}>
@@ -59,7 +60,7 @@ const StartPage = ({ children }) => {
</form>
</Paper>
</main>
- )
-}
+ );
+};
export default StartPage;
diff --git a/modern/src/UserPage.js b/modern/src/UserPage.js
index dfe8b98..6afbdf7 100644
--- a/modern/src/UserPage.js
+++ b/modern/src/UserPage.js
@@ -1,11 +1,13 @@
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t from './common/localization';
import userAttributes from './attributes/userAttributes';
import EditItemView from './EditItemView';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import EditAttributesView from './attributes/EditAttributesView';
import LinkField from './form/LinkField';
@@ -22,7 +24,8 @@ const UserPage = () => {
return (
<EditItemView endpoint="users" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -34,21 +37,24 @@ const UserPage = () => {
<TextField
margin="normal"
value={item.name || ''}
- onChange={event => setItem({...item, name: event.target.value})}
+ onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled" />
+ variant="filled"
+ />
<TextField
margin="normal"
value={item.email || ''}
- onChange={event => setItem({...item, email: event.target.value})}
+ onChange={(event) => setItem({ ...item, email: event.target.value })}
label={t('userEmail')}
- variant="filled" />
+ variant="filled"
+ />
<TextField
margin="normal"
type="password"
- onChange={event => setItem({...item, password: event.target.value})}
+ onChange={(event) => setItem({ ...item, password: event.target.value })}
label={t('userPassword')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -60,12 +66,13 @@ const UserPage = () => {
<AccordionDetails className={classes.details}>
<EditAttributesView
attributes={item.attributes}
- setAttributes={attributes => setItem({...item, attributes})}
+ setAttributes={(attributes) => setItem({ ...item, attributes })}
definitions={userAttributes}
- />
+ />
</AccordionDetails>
</Accordion>
- {item.id &&
+ {item.id
+ && (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="subtitle1">
@@ -76,28 +83,30 @@ const UserPage = () => {
<LinkField
margin="normal"
endpointAll="/api/devices?all=true"
- endpointLinked={"/api/devices?userId=" + item.id}
+ endpointLinked={`/api/devices?userId=${item.id}`}
baseId={item.id}
keyBase="userId"
keyLink="deviceId"
label={t('deviceTitle')}
- variant="filled" />
+ variant="filled"
+ />
<LinkField
margin="normal"
endpointAll="/api/groups?all=true"
- endpointLinked={"/api/groups?userId=" + item.id}
+ endpointLinked={`/api/groups?userId=${item.id}`}
baseId={item.id}
keyBase="userId"
keyLink="groupId"
label={t('settingsGroups')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
- }
+ )}
</>
- }
+ )}
</EditItemView>
);
-}
+};
export default UserPage;
diff --git a/modern/src/admin/ServerPage.js b/modern/src/admin/ServerPage.js
index 43664e5..7decac1 100644
--- a/modern/src/admin/ServerPage.js
+++ b/modern/src/admin/ServerPage.js
@@ -1,18 +1,20 @@
import React from 'react';
import TextField from '@material-ui/core/TextField';
-import t from '../common/localization';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Button, FormControl, Container, Checkbox, FormControlLabel } from '@material-ui/core';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Button, FormControl, Container, Checkbox, FormControlLabel,
+} from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
+import t from '../common/localization';
import MainToolbar from '../MainToolbar';
import { sessionActions } from '../store';
import EditAttributesView from '../attributes/EditAttributesView';
import deviceAttributes from '../attributes/deviceAttributes';
import userAttributes from '../attributes/userAttributes';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
container: {
marginTop: theme.spacing(2),
},
@@ -33,7 +35,7 @@ const ServerPage = () => {
const dispatch = useDispatch();
const classes = useStyles();
- const item = useSelector(state => state.session.server);
+ const item = useSelector((state) => state.session.server);
const setItem = (updatedItem) => dispatch(sessionActions.updateServer(updatedItem));
const handleSave = async () => {
@@ -51,8 +53,9 @@ const ServerPage = () => {
return (
<>
<MainToolbar />
- <Container maxWidth='xs' className={classes.container}>
- {item &&
+ <Container maxWidth="xs" className={classes.container}>
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -64,9 +67,10 @@ const ServerPage = () => {
<TextField
margin="normal"
value={item.announcement || ''}
- onChange={event => setItem({...item, announcement: event.target.value})}
+ onChange={(event) => setItem({ ...item, announcement: event.target.value })}
label={t('serverAnnouncement')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -77,17 +81,21 @@ const ServerPage = () => {
</AccordionSummary>
<AccordionDetails className={classes.details}>
<FormControlLabel
- control={<Checkbox checked={item.registration} onChange={event => setItem({...item, registration: event.target.checked})} />}
- label={t('serverRegistration')} />
+ control={<Checkbox checked={item.registration} onChange={(event) => setItem({ ...item, registration: event.target.checked })} />}
+ label={t('serverRegistration')}
+ />
<FormControlLabel
- control={<Checkbox checked={item.readonly} onChange={event => setItem({...item, readonly: event.target.checked})} />}
- label={t('serverReadonly')} />
+ control={<Checkbox checked={item.readonly} onChange={(event) => setItem({ ...item, readonly: event.target.checked })} />}
+ label={t('serverReadonly')}
+ />
<FormControlLabel
- control={<Checkbox checked={item.deviceReadonly} onChange={event => setItem({...item, deviceReadonly: event.target.checked})} />}
- label={t('userDeviceReadonly')} />
+ control={<Checkbox checked={item.deviceReadonly} onChange={(event) => setItem({ ...item, deviceReadonly: event.target.checked })} />}
+ label={t('userDeviceReadonly')}
+ />
<FormControlLabel
- control={<Checkbox checked={item.limitCommands} onChange={event => setItem({...item, limitCommands: event.target.checked})} />}
- label={t('userLimitCommands')} />
+ control={<Checkbox checked={item.limitCommands} onChange={(event) => setItem({ ...item, limitCommands: event.target.checked })} />}
+ label={t('userLimitCommands')}
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -99,19 +107,19 @@ const ServerPage = () => {
<AccordionDetails className={classes.details}>
<EditAttributesView
attributes={item.attributes}
- setAttributes={attributes => setItem({...item, attributes})}
- definitions={{...userAttributes, ...deviceAttributes}}
- />
+ setAttributes={(attributes) => setItem({ ...item, attributes })}
+ definitions={{ ...userAttributes, ...deviceAttributes }}
+ />
</AccordionDetails>
</Accordion>
</>
- }
- <FormControl fullWidth margin='normal'>
+ )}
+ <FormControl fullWidth margin="normal">
<div className={classes.buttons}>
- <Button type='button' color='primary' variant='outlined' onClick={() => history.goBack()}>
+ <Button type="button" color="primary" variant="outlined" onClick={() => history.goBack()}>
{t('sharedCancel')}
</Button>
- <Button type='button' color='primary' variant='contained' onClick={handleSave}>
+ <Button type="button" color="primary" variant="contained" onClick={handleSave}>
{t('sharedSave')}
</Button>
</div>
@@ -119,6 +127,6 @@ const ServerPage = () => {
</Container>
</>
);
-}
+};
export default ServerPage;
diff --git a/modern/src/admin/StatisticsPage.js b/modern/src/admin/StatisticsPage.js
index 1e440a4..131ab7e 100644
--- a/modern/src/admin/StatisticsPage.js
+++ b/modern/src/admin/StatisticsPage.js
@@ -1,10 +1,11 @@
-
import React, { useState } from 'react';
-import { FormControl, InputLabel,Select, MenuItem, TextField, Button, TableContainer, Table, TableRow, TableCell, TableHead, TableBody, Paper } from '@material-ui/core';
+import {
+ FormControl, InputLabel, Select, MenuItem, TextField, Button, TableContainer, Table, TableRow, TableCell, TableHead, TableBody, Paper,
+} from '@material-ui/core';
+import moment from 'moment';
import t from '../common/localization';
import { formatDate } from '../common/formatter';
import ReportLayoutPage from '../reports/ReportLayoutPage';
-import moment from 'moment';
const Filter = ({ setItems }) => {
const [period, setPeriod] = useState('today');
@@ -50,7 +51,7 @@ const Filter = ({ setItems }) => {
if (response.ok) {
setItems(await response.json());
}
- }
+ };
return (
<>
@@ -73,8 +74,9 @@ const Filter = ({ setItems }) => {
label={t('reportFrom')}
type="datetime-local"
value={from.format(moment.HTML5_FMT.DATETIME_LOCAL)}
- onChange={e => setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
- fullWidth />
+ onChange={(e) => setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
+ fullWidth
+ />
)}
{period === 'custom' && (
<TextField
@@ -83,16 +85,16 @@ const Filter = ({ setItems }) => {
label={t('reportTo')}
type="datetime-local"
value={to.format(moment.HTML5_FMT.DATETIME_LOCAL)}
- onChange={e => setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
- fullWidth />
+ onChange={(e) => setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
+ fullWidth
+ />
)}
<Button variant="contained" color="primary" onClick={handleClick} fullWidth>{t('reportShow')}</Button>
- </>
- )
-}
+ </>
+ );
+};
const StatisticsPage = () => {
-
const [items, setItems] = useState([]);
return (
@@ -125,7 +127,7 @@ const StatisticsPage = () => {
<TableCell>{item.mailSent}</TableCell>
<TableCell>{item.smsSent}</TableCell>
<TableCell>{item.geocoderRequests}</TableCell>
- <TableCell>{item.geolocationRequests}</TableCell>
+ <TableCell>{item.geolocationRequests}</TableCell>
</TableRow>
))}
</TableBody>
@@ -133,6 +135,6 @@ const StatisticsPage = () => {
</TableContainer>
</ReportLayoutPage>
);
-}
+};
export default StatisticsPage;
diff --git a/modern/src/admin/UsersPage.js b/modern/src/admin/UsersPage.js
index 630bea4..fc6e673 100644
--- a/modern/src/admin/UsersPage.js
+++ b/modern/src/admin/UsersPage.js
@@ -1,13 +1,15 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
-import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
+import {
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
+} from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
+import MainToolbar from '../MainToolbar';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
import { formatBoolean } from '../common/formatter';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
columnAction: {
width: theme.spacing(1),
padding: theme.spacing(0, 1),
@@ -28,43 +30,41 @@ const UsersView = ({ updateTimestamp, onMenuClick }) => {
return (
<TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell className={classes.columnAction} />
- <TableCell>{t('sharedName')}</TableCell>
- <TableCell>{t('userEmail')}</TableCell>
- <TableCell>{t('userAdmin')}</TableCell>
- <TableCell>{t('sharedDisabled')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {items.map((item) => (
- <TableRow key={item.id}>
- <TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
- <TableCell>{item.email}</TableCell>
- <TableCell>{formatBoolean(item, 'administrator')}</TableCell>
- <TableCell>{formatBoolean(item, 'disabled')}</TableCell>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedName')}</TableCell>
+ <TableCell>{t('userEmail')}</TableCell>
+ <TableCell>{t('userAdmin')}</TableCell>
+ <TableCell>{t('sharedDisabled')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <MoreVertIcon />
+ </IconButton>
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ <TableCell>{item.email}</TableCell>
+ <TableCell>{formatBoolean(item, 'administrator')}</TableCell>
+ <TableCell>{formatBoolean(item, 'disabled')}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
</TableContainer>
);
-}
+};
-const UsersPage = () => {
- return (
- <>
- <MainToolbar />
- <EditCollectionView content={UsersView} editPath="/user" endpoint="users" />
- </>
- );
-}
+const UsersPage = () => (
+ <>
+ <MainToolbar />
+ <EditCollectionView content={UsersView} editPath="/user" endpoint="users" />
+ </>
+);
export default UsersPage;
diff --git a/modern/src/attributes/AddAttributeDialog.js b/modern/src/attributes/AddAttributeDialog.js
index ee4c48c..24c208a 100644
--- a/modern/src/attributes/AddAttributeDialog.js
+++ b/modern/src/attributes/AddAttributeDialog.js
@@ -1,12 +1,14 @@
import React, { useState } from 'react';
-import { Button, Dialog, DialogActions, DialogContent, FormControl, InputLabel, MenuItem, Select, TextField } from "@material-ui/core";
+import {
+ Button, Dialog, DialogActions, DialogContent, FormControl, InputLabel, MenuItem, Select, TextField,
+} from '@material-ui/core';
-import t from '../common/localization';
import { Autocomplete, createFilterOptions } from '@material-ui/lab';
+import t from '../common/localization';
const AddAttributeDialog = ({ open, onResult, definitions }) => {
const filter = createFilterOptions({
- stringify: option => option.name,
+ stringify: (option) => option.name,
});
const options = Object.entries(definitions).map(([key, value]) => ({
@@ -39,10 +41,8 @@ const AddAttributeDialog = ({ open, onResult, definitions }) => {
return filtered;
}}
options={options}
- getOptionLabel={option => {
- return option && typeof option === 'object' ? option.name : option;
- }}
- renderOption={option => option.name}
+ getOptionLabel={(option) => (option && typeof option === 'object' ? option.name : option)}
+ renderOption={(option) => option.name}
freeSolo
renderInput={(params) => (
<TextField {...params} label={t('sharedAttribute')} variant="filled" margin="normal" />
@@ -52,14 +52,16 @@ const AddAttributeDialog = ({ open, onResult, definitions }) => {
variant="filled"
margin="normal"
fullWidth
- disabled={key in definitions}>
+ disabled={key in definitions}
+ >
<InputLabel>{t('sharedType')}</InputLabel>
<Select
value={type}
- onChange={e => setType(e.target.value)}>
- <MenuItem value={'string'}>{t('sharedTypeString')}</MenuItem>
- <MenuItem value={'number'}>{t('sharedTypeNumber')}</MenuItem>
- <MenuItem value={'boolean'}>{t('sharedTypeBoolean')}</MenuItem>
+ onChange={(e) => setType(e.target.value)}
+ >
+ <MenuItem value="string">{t('sharedTypeString')}</MenuItem>
+ <MenuItem value="number">{t('sharedTypeNumber')}</MenuItem>
+ <MenuItem value="boolean">{t('sharedTypeBoolean')}</MenuItem>
</Select>
</FormControl>
</DialogContent>
@@ -67,17 +69,19 @@ const AddAttributeDialog = ({ open, onResult, definitions }) => {
<Button
color="primary"
disabled={!key}
- onClick={() => onResult({ key, type })}>
+ onClick={() => onResult({ key, type })}
+ >
{t('sharedAdd')}
</Button>
<Button
autoFocus
- onClick={() => onResult(null)}>
+ onClick={() => onResult(null)}
+ >
{t('sharedCancel')}
</Button>
</DialogActions>
</Dialog>
- )
-}
+ );
+};
export default AddAttributeDialog;
diff --git a/modern/src/attributes/EditAttributesView.js b/modern/src/attributes/EditAttributesView.js
index 619d857..e38c02a 100644
--- a/modern/src/attributes/EditAttributesView.js
+++ b/modern/src/attributes/EditAttributesView.js
@@ -1,13 +1,14 @@
import React, { useState } from 'react';
-import t from '../common/localization';
-
-import { Button, Checkbox, FilledInput, FormControl, FormControlLabel, Grid, IconButton, InputAdornment, InputLabel, makeStyles } from "@material-ui/core";
+import {
+ Button, Checkbox, FilledInput, FormControl, FormControlLabel, Grid, IconButton, InputAdornment, InputLabel, makeStyles,
+} from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import AddIcon from '@material-ui/icons/Add';
+import t from '../common/localization';
import AddAttributeDialog from './AddAttributeDialog';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
addButton: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(1),
@@ -22,10 +23,36 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => {
const [addDialogShown, setAddDialogShown] = useState(false);
+ const updateAttribute = (key, value) => {
+ const updatedAttributes = { ...attributes };
+ updatedAttributes[key] = value;
+ setAttributes(updatedAttributes);
+ };
+
+ const deleteAttribute = (key) => {
+ const updatedAttributes = { ...attributes };
+ delete updatedAttributes[key];
+ setAttributes(updatedAttributes);
+ };
+
+ const getAttributeName = (key) => {
+ const definition = definitions[key];
+ return definition ? definition.name : key;
+ };
+
+ const getAttributeType = (value) => {
+ if (typeof value === 'number') {
+ return 'number';
+ } if (typeof value === 'boolean') {
+ return 'boolean';
+ }
+ return 'string';
+ };
+
const convertToList = (attributes) => {
- let booleanList = [];
- let otherList = [];
- for (const key in attributes) {
+ const booleanList = [];
+ const otherList = [];
+ Object.keys(attributes).forEach((key) => {
const value = attributes[key];
const type = getAttributeType(value);
if (type === 'boolean') {
@@ -33,14 +60,14 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => {
} else {
otherList.push({ key, value, type });
}
- }
+ });
return otherList.concat(booleanList);
- }
+ };
const handleAddResult = (definition) => {
setAddDialogShown(false);
if (definition) {
- switch(definition.type) {
+ switch (definition.type) {
case 'number':
updateAttribute(definition.key, 0);
break;
@@ -48,37 +75,10 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => {
updateAttribute(definition.key, false);
break;
default:
- updateAttribute(definition.key, "");
+ updateAttribute(definition.key, '');
break;
}
}
- }
-
- const updateAttribute = (key, value) => {
- let updatedAttributes = {...attributes};
- updatedAttributes[key] = value;
- setAttributes(updatedAttributes);
- };
-
- const deleteAttribute = (key) => {
- let updatedAttributes = {...attributes};
- delete updatedAttributes[key];
- setAttributes(updatedAttributes);
- };
-
- const getAttributeName = (key) => {
- const definition = definitions[key];
- return definition ? definition.name : key;
- };
-
- const getAttributeType = (value) => {
- if (typeof value === 'number') {
- return 'number';
- } else if (typeof value === 'boolean') {
- return 'boolean';
- } else {
- return 'string';
- }
};
return (
@@ -88,37 +88,37 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => {
return (
<Grid container direction="row" justify="space-between">
<FormControlLabel
- control={
+ control={(
<Checkbox
checked={value}
- onChange={e => updateAttribute(key, e.target.checked)}
- />
- }
- label={getAttributeName(key)} />
+ onChange={(e) => updateAttribute(key, e.target.checked)}
+ />
+ )}
+ label={getAttributeName(key)}
+ />
<IconButton className={classes.removeButton} onClick={() => deleteAttribute(key)}>
<CloseIcon />
</IconButton>
</Grid>
);
- } else {
- return (
- <FormControl variant="filled" margin="normal" key={key}>
- <InputLabel>{getAttributeName(key)}</InputLabel>
- <FilledInput
- type={type === 'number' ? 'number' : 'text'}
- value={value || ''}
- onChange={e => updateAttribute(key, e.target.value)}
- endAdornment={
- <InputAdornment position="end">
- <IconButton onClick={() => deleteAttribute(key)}>
- <CloseIcon />
- </IconButton>
- </InputAdornment>
- }
- />
- </FormControl>
- );
}
+ return (
+ <FormControl variant="filled" margin="normal" key={key}>
+ <InputLabel>{getAttributeName(key)}</InputLabel>
+ <FilledInput
+ type={type === 'number' ? 'number' : 'text'}
+ value={value || ''}
+ onChange={(e) => updateAttribute(key, e.target.value)}
+ endAdornment={(
+ <InputAdornment position="end">
+ <IconButton onClick={() => deleteAttribute(key)}>
+ <CloseIcon />
+ </IconButton>
+ </InputAdornment>
+ )}
+ />
+ </FormControl>
+ );
})}
<Button
size="large"
@@ -126,16 +126,17 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => {
color="primary"
onClick={() => setAddDialogShown(true)}
startIcon={<AddIcon />}
- className={classes.addButton}>
+ className={classes.addButton}
+ >
{t('sharedAdd')}
</Button>
<AddAttributeDialog
open={addDialogShown}
onResult={handleAddResult}
definitions={definitions}
- />
+ />
</>
);
-}
+};
export default EditAttributesView;
diff --git a/modern/src/attributes/deviceAttributes.js b/modern/src/attributes/deviceAttributes.js
index 891a225..26e3d92 100644
--- a/modern/src/attributes/deviceAttributes.js
+++ b/modern/src/attributes/deviceAttributes.js
@@ -1,7 +1,7 @@
-import t from '../common/localization'
+import t from '../common/localization';
export default {
- 'speedLimit': {
+ speedLimit: {
name: t('attributeSpeedLimit'),
type: 'string',
},
diff --git a/modern/src/attributes/geofenceAttributes.js b/modern/src/attributes/geofenceAttributes.js
index 4b9c9e6..59a8869 100644
--- a/modern/src/attributes/geofenceAttributes.js
+++ b/modern/src/attributes/geofenceAttributes.js
@@ -1,7 +1,7 @@
-import t from '../common/localization'
+import t from '../common/localization';
export default {
- 'speedLimit': {
+ speedLimit: {
name: t('attributeSpeedLimit'),
type: 'string',
},
diff --git a/modern/src/attributes/positionAttributes.js b/modern/src/attributes/positionAttributes.js
index b1efe3d..94f396a 100644
--- a/modern/src/attributes/positionAttributes.js
+++ b/modern/src/attributes/positionAttributes.js
@@ -1,19 +1,19 @@
-import t from '../common/localization'
+import t from '../common/localization';
export default {
- 'raw': {
+ raw: {
name: t('positionRaw'),
type: 'string',
},
- 'index': {
+ index: {
name: t('positionIndex'),
type: 'number',
},
- 'ignition': {
+ ignition: {
name: t('positionIgnition'),
type: 'boolean',
},
- 'odometer': {
+ odometer: {
name: t('positionOdometer'),
type: 'number',
dataType: 'distance',
diff --git a/modern/src/attributes/userAttributes.js b/modern/src/attributes/userAttributes.js
index bcec29f..6f842f9 100644
--- a/modern/src/attributes/userAttributes.js
+++ b/modern/src/attributes/userAttributes.js
@@ -1,7 +1,7 @@
-import t from '../common/localization'
+import t from '../common/localization';
export default {
- 'notificationTokens': {
+ notificationTokens: {
name: t('attributeNotificationTokens'),
type: 'string',
},
@@ -49,19 +49,19 @@ export default {
name: t('attributeUiHidePositionAttributes'),
type: 'string',
},
- 'distanceUnit': {
+ distanceUnit: {
name: t('settingsDistanceUnit'),
type: 'string',
},
- 'speedUnit': {
+ speedUnit: {
name: t('settingsSpeedUnit'),
type: 'string',
},
- 'volumeUnit': {
+ volumeUnit: {
name: t('settingsVolumeUnit'),
type: 'string',
},
- 'timezone': {
+ timezone: {
name: t('sharedTimezone'),
type: 'string',
},
diff --git a/modern/src/common/converter.js b/modern/src/common/converter.js
index 9cdc623..d45db5d 100644
--- a/modern/src/common/converter.js
+++ b/modern/src/common/converter.js
@@ -1,4 +1,4 @@
-const speedConverter = unit => {
+const speedConverter = (unit) => {
switch (unit) {
case 'kmh':
return 1.852;
@@ -10,7 +10,7 @@ const speedConverter = unit => {
}
};
-const distanceConverter = unit => {
+const distanceConverter = (unit) => {
switch (unit) {
case 'mi':
return 0.000621371;
@@ -19,21 +19,13 @@ const distanceConverter = unit => {
case 'km':
default:
return 0.001;
- }
-}
+ }
+};
-export const speedFromKnots = (value, unit) => {
- return value * speedConverter(unit);
-}
+export const speedFromKnots = (value, unit) => value * speedConverter(unit);
-export const speedToKnots = (value, unit) => {
- return value / speedConverter(unit);
-}
+export const speedToKnots = (value, unit) => value / speedConverter(unit);
-export const distanceFromMeters = (value, unit) => {
- return value * distanceConverter(unit);
-}
+export const distanceFromMeters = (value, unit) => value * distanceConverter(unit);
-export const distanceToMeters = (value, unit) => {
- return value / distanceConverter(unit);
-}
+export const distanceToMeters = (value, unit) => value / distanceConverter(unit);
diff --git a/modern/src/common/deviceCategories.js b/modern/src/common/deviceCategories.js
index 1eda190..f5d749a 100644
--- a/modern/src/common/deviceCategories.js
+++ b/modern/src/common/deviceCategories.js
@@ -1,4 +1,4 @@
-export const deviceCategories = [
+export default [
'default',
'animal',
'bicycle',
diff --git a/modern/src/common/formatter.js b/modern/src/common/formatter.js
index 0d8ac4c..3c0341b 100644
--- a/modern/src/common/formatter.js
+++ b/modern/src/common/formatter.js
@@ -1,5 +1,11 @@
import moment from 'moment';
-import t from '../common/localization';
+import t from './localization';
+
+export const formatBoolean = (value) => (value ? t('sharedYes') : t('sharedNo'));
+
+export const formatNumber = (value, precision = 1) => Number(value.toFixed(precision));
+
+export const formatDate = (value, format = 'YYYY-MM-DD HH:mm') => moment(value).format(format);
export const formatPosition = (value, key) => {
if (value != null && typeof value === 'object') {
@@ -18,30 +24,17 @@ export const formatPosition = (value, key) => {
case 'course':
return value.toFixed(1);
case 'batteryLevel':
- return value + '%';
+ return `${value}%`;
default:
if (typeof value === 'number') {
return formatNumber(value);
- } else if (typeof value === 'boolean') {
+ } if (typeof value === 'boolean') {
return formatBoolean(value);
- } else {
- return value;
}
+ return value;
}
};
-export const formatBoolean = (value) => {
- return value ? t('sharedYes') : t('sharedNo');
-};
-
-export const formatNumber = (value, precision = 1) => {
- return Number(value.toFixed(precision));
-};
-
-export const formatDate = (value, format = 'YYYY-MM-DD HH:mm') => {
- return moment(value).format(format);
-};
-
export const formatDistance = (value, unit) => {
switch (unit) {
case 'mi':
@@ -50,7 +43,7 @@ export const formatDistance = (value, unit) => {
return `${(value * 0.000539957).toFixed(2)} ${t('sharedNmi')}`;
case 'km':
default:
- return `${(value * 0.001).toFixed(2)} ${t('sharedKm')}`;
+ return `${(value * 0.001).toFixed(2)} ${t('sharedKm')}`;
}
};
@@ -62,8 +55,8 @@ export const formatSpeed = (value, unit) => {
return `${(value * 1.15078).toFixed(2)} ${t('sharedMph')}`;
case 'kn':
default:
- return `${(value * 1).toFixed(2)} ${t('sharedKn')}`;
- }
+ return `${(value * 1).toFixed(2)} ${t('sharedKn')}`;
+ }
};
export const formatVolume = (value, unit) => {
@@ -74,16 +67,15 @@ export const formatVolume = (value, unit) => {
return `${(value / 3.785).toFixed(2)} ${t('sharedGallonAbbreviation')}`;
case 'ltr':
default:
- return `${(value / 1).toFixed(2)} ${t('sharedLiterAbbreviation')}`;
- }
-}
-
-export const formatHours = (value) => {
- return moment.duration(value).humanize();
+ return `${(value / 1).toFixed(2)} ${t('sharedLiterAbbreviation')}`;
+ }
};
+export const formatHours = (value) => moment.duration(value).humanize();
+
export const formatCoordinate = (key, value, unit) => {
- var hemisphere, degrees, minutes, seconds;
+ let hemisphere; let degrees; let minutes; let
+ seconds;
if (key === 'latitude') {
hemisphere = value >= 0 ? 'N' : 'S';
} else {
@@ -95,14 +87,14 @@ export const formatCoordinate = (key, value, unit) => {
value = Math.abs(value);
degrees = Math.floor(value);
minutes = (value - degrees) * 60;
- return degrees + 'Ā° ' + minutes.toFixed(6) + '\' ' + hemisphere;
+ return `${degrees}Ā° ${minutes.toFixed(6)}' ${hemisphere}`;
case 'dms':
value = Math.abs(value);
degrees = Math.floor(value);
minutes = Math.floor((value - degrees) * 60);
seconds = Math.round((value - degrees - minutes / 60) * 3600);
- return degrees + 'Ā° ' + minutes + '\' ' + seconds + '" ' + hemisphere;
+ return `${degrees}Ā° ${minutes}' ${seconds}" ${hemisphere}`;
default:
- return value.toFixed(6) + 'Ā°';
- }
+ return `${value.toFixed(6)}Ā°`;
+ }
};
diff --git a/modern/src/common/localization.js b/modern/src/common/localization.js
index cb1420b..9e2123a 100644
--- a/modern/src/common/localization.js
+++ b/modern/src/common/localization.js
@@ -54,60 +54,60 @@ import zh from '../../../web/l10n/zh.json';
import zh_TW from '../../../web/l10n/zh_TW.json';
const supportedLanguages = {
- 'af': { data: af, name: 'Afrikaans' },
- 'ar': { data: ar, name: 'Ų§Ł„Ų¹Ų±ŲØŁŠŲ©' },
- 'az': { data: az, name: 'Azərbaycanca' },
- 'bg': { data: bg, name: 'Š‘ŃŠŠ»Š³Š°Ń€ŃŠŗŠø' },
- 'bn': { data: bn, name: 'ą¦¬ą¦¾ą¦‚ą¦²ą¦¾' },
- 'cs': { data: cs, name: 'ČeÅ”tina' },
- 'de': { data: de, name: 'Deutsch' },
- 'da': { data: da, name: 'Dansk' },
- 'el': { data: el, name: 'Ī•Ī»Ī»Ī·Ī½Ī¹ĪŗĪ¬' },
- 'en': { data: en, name: 'English' },
- 'es': { data: es, name: 'EspaƱol' },
- 'fa': { data: fa, name: 'ŁŲ§Ų±Ų³ŪŒ' },
- 'fi': { data: fi, name: 'Suomi' },
- 'fr': { data: fr, name: 'FranƧais' },
- 'he': { data: he, name: 'עב×Øי×Ŗ' },
- 'hi': { data: hi, name: 'ą¤¹ą¤æą¤Øą„ą¤¦ą„€' },
- 'hr': { data: hr, name: 'Hrvatski' },
- 'hu': { data: hu, name: 'Magyar' },
- 'id': { data: id, name: 'Bahasa Indonesia' },
- 'it': { data: it, name: 'Italiano' },
- 'ja': { data: ja, name: 'ę—„ęœ¬čŖž' },
- 'ka': { data: ka, name: 'įƒ„įƒįƒ įƒ—įƒ£įƒšįƒ˜' },
- 'kk': { data: kk, name: 'ŅšŠ°Š·Š°Ņ›ŃˆŠ°' },
- 'ko': { data: ko, name: 'ķ•œźµ­ģ–“' },
- 'km': { data: km, name: 'įž—įž¶įžŸįž¶įžįŸ’įž˜įŸ‚įžš' },
- 'lo': { data: lo, name: 'ąŗ„ąŗ²ąŗ§' },
- 'lt': { data: lt, name: 'Lietuvių' },
- 'lv': { data: lv, name: 'LatvieŔu' },
- 'ml': { data: ml, name: 'ą“®ą“²ą“Æą“¾ą“³ą“‚' },
- 'mn': { data: mn, name: 'ŠœŠ¾Š½Š³Š¾Š» хэŠ»' },
- 'ms': { data: ms, name: 'ŲØŁ‡Ų§Ų³ Ł…Ł„Ų§ŁŠŁˆ' },
- 'nb': { data: nb, name: 'Norsk bokmƄl' },
- 'ne': { data: ne, name: 'ą¤Øą„‡ą¤Ŗą¤¾ą¤²ą„€' },
- 'nl': { data: nl, name: 'Nederlands' },
- 'nn': { data: nn, name: 'Norsk nynorsk' },
- 'pl': { data: pl, name: 'Polski' },
- 'pt': { data: pt, name: 'PortuguĆŖs' },
- 'pt_BR': { data: pt_BR, name: 'PortuguĆŖs (Brasil)' },
- 'ro': { data: ro, name: 'RomĆ¢nă' },
- 'ru': { data: ru, name: 'Š ŃƒŃŃŠŗŠøŠ¹' },
- 'si': { data: si, name: 'ą·ƒą·’ą¶‚ą·„ą¶½' },
- 'sk': { data: sk, name: 'Slovenčina' },
- 'sl': { data: sl, name: 'SlovenŔčina' },
- 'sq': { data: sq, name: 'Shqipƫria' },
- 'sr': { data: sr, name: 'Srpski' },
- 'sv': { data: sv, name: 'Svenska' },
- 'ta': { data: ta, name: 'ą®¤ą®®ą®æą®“ąÆ' },
- 'th': { data: th, name: 'ą¹„ąø—ąø¢' },
- 'tr': { data: tr, name: 'TĆ¼rkƧe' },
- 'uk': { data: uk, name: 'Š£ŠŗрŠ°Ń—Š½ŃŃŒŠŗŠ°' },
- 'uz': { data: uz, name: 'OŹ»zbekcha' },
- 'vi': { data: vi, name: 'Tiįŗæng Viį»‡t' },
- 'zh': { data: zh, name: 'äø­ę–‡' },
- 'zh_TW': { data: zh_TW, name: 'äø­ę–‡ (Taiwan)' }
+ af: { data: af, name: 'Afrikaans' },
+ ar: { data: ar, name: 'Ų§Ł„Ų¹Ų±ŲØŁŠŲ©' },
+ az: { data: az, name: 'Azərbaycanca' },
+ bg: { data: bg, name: 'Š‘ŃŠŠ»Š³Š°Ń€ŃŠŗŠø' },
+ bn: { data: bn, name: 'ą¦¬ą¦¾ą¦‚ą¦²ą¦¾' },
+ cs: { data: cs, name: 'ČeÅ”tina' },
+ de: { data: de, name: 'Deutsch' },
+ da: { data: da, name: 'Dansk' },
+ el: { data: el, name: 'Ī•Ī»Ī»Ī·Ī½Ī¹ĪŗĪ¬' },
+ en: { data: en, name: 'English' },
+ es: { data: es, name: 'EspaƱol' },
+ fa: { data: fa, name: 'ŁŲ§Ų±Ų³ŪŒ' },
+ fi: { data: fi, name: 'Suomi' },
+ fr: { data: fr, name: 'FranƧais' },
+ he: { data: he, name: 'עב×Øי×Ŗ' },
+ hi: { data: hi, name: 'ą¤¹ą¤æą¤Øą„ą¤¦ą„€' },
+ hr: { data: hr, name: 'Hrvatski' },
+ hu: { data: hu, name: 'Magyar' },
+ id: { data: id, name: 'Bahasa Indonesia' },
+ it: { data: it, name: 'Italiano' },
+ ja: { data: ja, name: 'ę—„ęœ¬čŖž' },
+ ka: { data: ka, name: 'įƒ„įƒįƒ įƒ—įƒ£įƒšįƒ˜' },
+ kk: { data: kk, name: 'ŅšŠ°Š·Š°Ņ›ŃˆŠ°' },
+ ko: { data: ko, name: 'ķ•œźµ­ģ–“' },
+ km: { data: km, name: 'įž—įž¶įžŸįž¶įžįŸ’įž˜įŸ‚įžš' },
+ lo: { data: lo, name: 'ąŗ„ąŗ²ąŗ§' },
+ lt: { data: lt, name: 'Lietuvių' },
+ lv: { data: lv, name: 'LatvieŔu' },
+ ml: { data: ml, name: 'ą“®ą“²ą“Æą“¾ą“³ą“‚' },
+ mn: { data: mn, name: 'ŠœŠ¾Š½Š³Š¾Š» хэŠ»' },
+ ms: { data: ms, name: 'ŲØŁ‡Ų§Ų³ Ł…Ł„Ų§ŁŠŁˆ' },
+ nb: { data: nb, name: 'Norsk bokmƄl' },
+ ne: { data: ne, name: 'ą¤Øą„‡ą¤Ŗą¤¾ą¤²ą„€' },
+ nl: { data: nl, name: 'Nederlands' },
+ nn: { data: nn, name: 'Norsk nynorsk' },
+ pl: { data: pl, name: 'Polski' },
+ pt: { data: pt, name: 'PortuguĆŖs' },
+ pt_BR: { data: pt_BR, name: 'PortuguĆŖs (Brasil)' },
+ ro: { data: ro, name: 'RomĆ¢nă' },
+ ru: { data: ru, name: 'Š ŃƒŃŃŠŗŠøŠ¹' },
+ si: { data: si, name: 'ą·ƒą·’ą¶‚ą·„ą¶½' },
+ sk: { data: sk, name: 'Slovenčina' },
+ sl: { data: sl, name: 'SlovenŔčina' },
+ sq: { data: sq, name: 'Shqipƫria' },
+ sr: { data: sr, name: 'Srpski' },
+ sv: { data: sv, name: 'Svenska' },
+ ta: { data: ta, name: 'ą®¤ą®®ą®æą®“ąÆ' },
+ th: { data: th, name: 'ą¹„ąø—ąø¢' },
+ tr: { data: tr, name: 'TĆ¼rkƧe' },
+ uk: { data: uk, name: 'Š£ŠŗрŠ°Ń—Š½ŃŃŒŠŗŠ°' },
+ uz: { data: uz, name: 'OŹ»zbekcha' },
+ vi: { data: vi, name: 'Tiįŗæng Viį»‡t' },
+ zh: { data: zh, name: 'äø­ę–‡' },
+ zh_TW: { data: zh_TW, name: 'äø­ę–‡ (Taiwan)' },
};
const languages = window.navigator.languages !== undefined ? window.navigator.languages.slice() : [];
@@ -130,10 +130,6 @@ for (let i = 0; i < languages.length; i++) {
const selectedLanguage = supportedLanguages[language];
-export const findStringKeys = (predicate) => {
- return Object.keys(selectedLanguage.data).filter(predicate);
-}
+export const findStringKeys = (predicate) => Object.keys(selectedLanguage.data).filter(predicate);
-export default key => {
- return selectedLanguage.data[key];
-};
+export default (key) => selectedLanguage.data[key];
diff --git a/modern/src/common/preferences.js b/modern/src/common/preferences.js
index 24fe389..aba3c82 100644
--- a/modern/src/common/preferences.js
+++ b/modern/src/common/preferences.js
@@ -1,21 +1,15 @@
import { useSelector } from 'react-redux';
-export const usePreference = (key, defaultValue) => {
- return useSelector(state => {
- if (state.session.server.forceSettings) {
- return state.session.server[key] || state.session.user[key] || defaultValue;
- } else {
- return state.session.user[key] || state.session.server[key] || defaultValue;
- }
- });
-};
+export const usePreference = (key, defaultValue) => useSelector((state) => {
+ if (state.session.server.forceSettings) {
+ return state.session.server[key] || state.session.user[key] || defaultValue;
+ }
+ return state.session.user[key] || state.session.server[key] || defaultValue;
+});
-export const useAttributePreference = (key, defaultValue) => {
- return useSelector(state => {
- if (state.session.server.forceSettings) {
- return state.session.server.attributes[key] || state.session.user.attributes[key] || defaultValue;
- } else {
- return state.session.user.attributes[key] || state.session.server.attributes[key] || defaultValue;
- }
- });
-};
+export const useAttributePreference = (key, defaultValue) => useSelector((state) => {
+ if (state.session.server.forceSettings) {
+ return state.session.server.attributes[key] || state.session.user.attributes[key] || defaultValue;
+ }
+ return state.session.user.attributes[key] || state.session.server.attributes[key] || defaultValue;
+});
diff --git a/modern/src/common/stringUtils.js b/modern/src/common/stringUtils.js
index 7bd68c8..fc997fe 100644
--- a/modern/src/common/stringUtils.js
+++ b/modern/src/common/stringUtils.js
@@ -1,7 +1,3 @@
-export const prefixString = (prefix, value) => {
- return prefix + value.charAt(0).toUpperCase() + value.slice(1);
-}
+export const prefixString = (prefix, value) => prefix + value.charAt(0).toUpperCase() + value.slice(1);
-export const unprefixString = (prefix, value) => {
- return value.charAt(prefix.length).toLowerCase() + value.slice(prefix.length + 1);
-}
+export const unprefixString = (prefix, value) => value.charAt(prefix.length).toLowerCase() + value.slice(prefix.length + 1);
diff --git a/modern/src/components/registration/LoginForm.js b/modern/src/components/registration/LoginForm.js
index 382b4fd..e083541 100644
--- a/modern/src/components/registration/LoginForm.js
+++ b/modern/src/components/registration/LoginForm.js
@@ -1,24 +1,25 @@
import React, { useState } from 'react';
-import { Grid, useMediaQuery, makeStyles, InputLabel, Select, MenuItem, FormControl, Button, TextField, Link } from '@material-ui/core';
+import {
+ Grid, useMediaQuery, makeStyles, InputLabel, Select, MenuItem, FormControl, Button, TextField, Link,
+} from '@material-ui/core';
import { useTheme } from '@material-ui/core/styles';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { sessionActions } from '../../store';
import t from '../../common/localization';
-import StartPage from './../../StartPage';
+import StartPage from '../../StartPage';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
logoContainer: {
textAlign: 'center',
color: theme.palette.primary.main,
},
resetPassword: {
cursor: 'pointer',
- }
+ },
}));
const LoginForm = () => {
-
const classes = useStyles();
const dispatch = useDispatch();
const history = useHistory();
@@ -27,16 +28,16 @@ const LoginForm = () => {
const [failed, setFailed] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
- const registrationEnabled = useSelector(state => state.session.server ? state.session.server['registration'] : false);
- const emailEnabled = useSelector(state => state.session.server ? state.session.server['emailEnabled'] : false);
+ const registrationEnabled = useSelector((state) => (state.session.server ? state.session.server.registration : false));
+ const emailEnabled = useSelector((state) => (state.session.server ? state.session.server.emailEnabled : false));
const handleEmailChange = (event) => {
setEmail(event.target.value);
- }
+ };
const handlePasswordChange = (event) => {
setPassword(event.target.value);
- }
+ };
const handleLogin = async (event) => {
event.preventDefault();
@@ -49,38 +50,40 @@ const LoginForm = () => {
setFailed(true);
setPassword('');
}
- }
+ };
- const handleSpecialKey = e => {
+ const handleSpecialKey = (e) => {
if (e.keyCode === 13 && email && password) {
handleLogin(e);
}
- }
+ };
return (
<StartPage>
- <Grid container direction='column' spacing={2}>
- {useMediaQuery(theme.breakpoints.down('md')) &&
+ <Grid container direction="column" spacing={2}>
+ {useMediaQuery(theme.breakpoints.down('md'))
+ && (
<Grid item className={classes.logoContainer}>
<svg height="64" width="240">
- <use xlinkHref="/logo.svg#img"></use>
+ <use xlinkHref="/logo.svg#img" />
</svg>
</Grid>
- }
+ )}
<Grid item>
<TextField
required
fullWidth
error={failed}
label={t('userEmail')}
- name='email'
+ name="email"
value={email}
- autoComplete='email'
+ autoComplete="email"
autoFocus
onChange={handleEmailChange}
onKeyUp={handleSpecialKey}
helperText={failed && 'Invalid username or password'}
- variant='filled' />
+ variant="filled"
+ />
</Grid>
<Grid item>
<TextField
@@ -88,22 +91,24 @@ const LoginForm = () => {
fullWidth
error={failed}
label={t('userPassword')}
- name='password'
+ name="password"
value={password}
- type='password'
- autoComplete='current-password'
+ type="password"
+ autoComplete="current-password"
onChange={handlePasswordChange}
onKeyUp={handleSpecialKey}
- variant='filled' />
+ variant="filled"
+ />
</Grid>
<Grid item>
- <Button
+ <Button
onClick={handleLogin}
onKeyUp={handleSpecialKey}
- variant='contained'
- color='secondary'
+ variant="contained"
+ color="secondary"
disabled={!email || !password}
- fullWidth>
+ fullWidth
+ >
{t('loginLogin')}
</Button>
</Grid>
@@ -122,14 +127,16 @@ const LoginForm = () => {
</FormControl>
</Grid>
</Grid>
- {emailEnabled && <Grid item container justify="flex-end">
+ {emailEnabled && (
+ <Grid item container justify="flex-end">
<Grid item>
- <Link onClick={() => history.push('/reset-password')} className={classes.resetPassword} underline="none">{t('loginReset')}</Link>
+ <Link onClick={() => history.push('/reset-password')} className={classes.resetPassword} underline="none">{t('loginReset')}</Link>
</Grid>
- </Grid>}
+ </Grid>
+ )}
</Grid>
</StartPage>
- )
-}
+ );
+};
export default LoginForm;
diff --git a/modern/src/components/registration/RegisterForm.js b/modern/src/components/registration/RegisterForm.js
index b2a8222..06f5355 100644
--- a/modern/src/components/registration/RegisterForm.js
+++ b/modern/src/components/registration/RegisterForm.js
@@ -1,27 +1,28 @@
import React, { useState } from 'react';
-import { Grid, Button, TextField, Typography, Link, makeStyles, Snackbar } from '@material-ui/core';
+import {
+ Grid, Button, TextField, Typography, Link, makeStyles, Snackbar,
+} from '@material-ui/core';
import { useHistory } from 'react-router-dom';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
-import StartPage from './../../StartPage';
-import t from './../../common/localization';
+import StartPage from '../../StartPage';
+import t from '../../common/localization';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
register: {
fontSize: theme.spacing(3),
fontWeight: 500,
marginLeft: theme.spacing(2),
- textTransform: "uppercase"
+ textTransform: 'uppercase',
},
link: {
fontSize: theme.spacing(3),
fontWeight: 500,
marginTop: theme.spacing(0.5),
- cursor: 'pointer'
- }
+ cursor: 'pointer',
+ },
}));
const RegisterForm = () => {
-
const classes = useStyles();
const history = useHistory();
@@ -30,21 +31,19 @@ const RegisterForm = () => {
const [password, setPassword] = useState('');
const [snackbarOpen, setSnackbarOpen] = useState(false);
- const submitDisabled = () => {
- return !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password;
- }
+ const submitDisabled = () => !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password;
const handleRegister = async () => {
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({name, email, password})
+ body: JSON.stringify({ name, email, password }),
});
if (response.ok) {
setSnackbarOpen(true);
- }
- }
+ }
+ };
return (
<StartPage>
@@ -53,18 +52,19 @@ const RegisterForm = () => {
open={snackbarOpen}
onClose={() => history.push('/login')}
autoHideDuration={6000}
- message={t('loginCreated')} />
- <Grid container direction='column' spacing={2}>
+ message={t('loginCreated')}
+ />
+ <Grid container direction="column" spacing={2}>
<Grid container item>
<Grid item>
- <Typography className={classes.link} color='primary'>
+ <Typography className={classes.link} color="primary">
<Link onClick={() => history.push('/login')}>
<ArrowBackIcon />
</Link>
</Typography>
</Grid>
<Grid item xs>
- <Typography className={classes.register} color='primary'>
+ <Typography className={classes.register} color="primary">
{t('loginRegister')}
</Typography>
</Grid>
@@ -74,50 +74,54 @@ const RegisterForm = () => {
required
fullWidth
label={t('sharedName')}
- name='name'
+ name="name"
value={name || ''}
- autoComplete='name'
+ autoComplete="name"
autoFocus
- onChange={event => setName(event.target.value)}
- variant='filled' />
+ onChange={(event) => setName(event.target.value)}
+ variant="filled"
+ />
</Grid>
<Grid item>
<TextField
required
fullWidth
- type='email'
+ type="email"
label={t('userEmail')}
- name='email'
+ name="email"
value={email || ''}
- autoComplete='email'
- onChange={event => setEmail(event.target.value)}
- variant='filled' />
+ autoComplete="email"
+ onChange={(event) => setEmail(event.target.value)}
+ variant="filled"
+ />
</Grid>
<Grid item>
<TextField
required
fullWidth
label={t('userPassword')}
- name='password'
+ name="password"
value={password || ''}
- type='password'
- autoComplete='current-password'
- onChange={event => setPassword(event.target.value)}
- variant='filled' />
+ type="password"
+ autoComplete="current-password"
+ onChange={(event) => setPassword(event.target.value)}
+ variant="filled"
+ />
</Grid>
<Grid item>
<Button
- variant='contained'
- color="secondary"
- onClick={handleRegister}
+ variant="contained"
+ color="secondary"
+ onClick={handleRegister}
disabled={submitDisabled()}
- fullWidth>
- {t('loginRegister')}
+ fullWidth
+ >
+ {t('loginRegister')}
</Button>
</Grid>
</Grid>
</StartPage>
- )
-}
+ );
+};
export default RegisterForm;
diff --git a/modern/src/components/registration/ResetPasswordForm.js b/modern/src/components/registration/ResetPasswordForm.js
index c268f80..f4dd2e4 100644
--- a/modern/src/components/registration/ResetPasswordForm.js
+++ b/modern/src/components/registration/ResetPasswordForm.js
@@ -1,12 +1,9 @@
import React from 'react';
-const ResetPasswordForm = () => {
-
- return (
- <>
- <div>Reset Password Comming Soon!!!</div>
- </>
- )
-}
+const ResetPasswordForm = () => (
+ <>
+ <div>Reset Password Comming Soon!!!</div>
+ </>
+);
export default ResetPasswordForm;
diff --git a/modern/src/components/reports/ReportNavbar.js b/modern/src/components/reports/ReportNavbar.js
index ac01fad..16807e8 100644
--- a/modern/src/components/reports/ReportNavbar.js
+++ b/modern/src/components/reports/ReportNavbar.js
@@ -1,26 +1,28 @@
import React from 'react';
-import { AppBar, Toolbar, Typography, IconButton } from '@material-ui/core';
+import {
+ AppBar, Toolbar, Typography, IconButton,
+} from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
import t from '../../common/localization';
-const ReportNavbar = ({ setOpenDrawer, reportTitle }) => {
-
- return (
- <AppBar position="fixed" color="inherit">
- <Toolbar>
- <IconButton
- color="inherit"
- aria-label="open drawer"
- edge="start"
- onClick={() => setOpenDrawer(true)}>
- <MenuIcon />
- </IconButton>
- <Typography variant="h6" noWrap>
- {t('reportTitle')} {` / ${reportTitle}`}
- </Typography>
- </Toolbar>
- </AppBar>
- )
-}
+const ReportNavbar = ({ setOpenDrawer, reportTitle }) => (
+ <AppBar position="fixed" color="inherit">
+ <Toolbar>
+ <IconButton
+ color="inherit"
+ aria-label="open drawer"
+ edge="start"
+ onClick={() => setOpenDrawer(true)}
+ >
+ <MenuIcon />
+ </IconButton>
+ <Typography variant="h6" noWrap>
+ {t('reportTitle')}
+ {' '}
+ {` / ${reportTitle}`}
+ </Typography>
+ </Toolbar>
+ </AppBar>
+);
export default ReportNavbar;
diff --git a/modern/src/components/reports/ReportSidebar.js b/modern/src/components/reports/ReportSidebar.js
index 90e20c0..686fc04 100644
--- a/modern/src/components/reports/ReportSidebar.js
+++ b/modern/src/components/reports/ReportSidebar.js
@@ -1,21 +1,23 @@
import React from 'react';
-import { List, ListItem, ListItemText, ListItemIcon } from '@material-ui/core';
+import {
+ List, ListItem, ListItemText, ListItemIcon,
+} from '@material-ui/core';
import { Link, useLocation } from 'react-router-dom';
const ReportSidebar = ({ routes }) => {
-
const location = useLocation();
return (
- <List disablePadding style={{paddingTop: '16px'}}>
- {routes.map((route, index) => (
+ <List disablePadding style={{ paddingTop: '16px' }}>
+ {routes.map((route) => (
<ListItem
disableRipple
component={Link}
- key={`${route}${index}`}
+ key={route}
button
to={route.href}
- selected={route.href === location.pathname}>
+ selected={route.href === location.pathname}
+ >
<ListItemIcon>
{route.icon}
</ListItemIcon>
@@ -23,7 +25,7 @@ const ReportSidebar = ({ routes }) => {
</ListItem>
))}
</List>
- )
-}
+ );
+};
export default ReportSidebar;
diff --git a/modern/src/form/LinkField.js b/modern/src/form/LinkField.js
index b228fb3..81467a1 100644
--- a/modern/src/form/LinkField.js
+++ b/modern/src/form/LinkField.js
@@ -1,4 +1,6 @@
-import { FormControl, InputLabel, MenuItem, Select } from '@material-ui/core';
+import {
+ FormControl, InputLabel, MenuItem, Select,
+} from '@material-ui/core';
import React, { useState } from 'react';
import { useEffectAsync } from '../reactHelper';
@@ -11,8 +13,8 @@ const LinkField = ({
baseId,
keyBase,
keyLink,
- keyGetter = item => item.id,
- titleGetter = item => item.name,
+ keyGetter = (item) => item.id,
+ titleGetter = (item) => item.name,
}) => {
const [items, setItems] = useState();
const [linked, setLinked] = useState();
@@ -28,34 +30,36 @@ const LinkField = ({
const response = await fetch(endpointLinked);
if (response.ok) {
const data = await response.json();
- setLinked(data.map(it => it.id));
+ setLinked(data.map((it) => it.id));
}
}, []);
- const createBody = linkId => {
+ const createBody = (linkId) => {
const body = {};
body[keyBase] = baseId;
body[keyLink] = linkId;
return body;
- }
+ };
- const onChange = async event => {
+ const onChange = async (event) => {
const oldValue = linked;
const newValue = event.target.value;
- for (const added of newValue.filter(it => !oldValue.includes(it))) {
- await fetch('/api/permissions', {
+ const results = [];
+ newValue.filter((it) => !oldValue.includes(it)).forEach((added) => {
+ results.push(fetch('/api/permissions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(createBody(added)),
- });
- }
- for (const removed of oldValue.filter(it => !newValue.includes(it))) {
- await fetch('/api/permissions', {
+ }));
+ });
+ oldValue.filter((it) => !newValue.includes(it)).forEach((removed) => {
+ results.push(fetch('/api/permissions', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(createBody(removed)),
- });
- }
+ }));
+ });
+ await Promise.all(results);
setLinked(newValue);
};
@@ -66,16 +70,16 @@ const LinkField = ({
<Select
multiple
value={linked}
- onChange={onChange}>
- {items.map(item => (
+ onChange={onChange}
+ >
+ {items.map((item) => (
<MenuItem key={keyGetter(item)} value={keyGetter(item)}>{titleGetter(item)}</MenuItem>
))}
</Select>
</FormControl>
);
- } else {
- return null;
}
-}
+ return null;
+};
export default LinkField;
diff --git a/modern/src/form/SelectField.js b/modern/src/form/SelectField.js
index b179c58..303d203 100644
--- a/modern/src/form/SelectField.js
+++ b/modern/src/form/SelectField.js
@@ -1,4 +1,6 @@
-import { FormControl, InputLabel, MenuItem, Select } from '@material-ui/core';
+import {
+ FormControl, InputLabel, MenuItem, Select,
+} from '@material-ui/core';
import React, { useState } from 'react';
import { useEffectAsync } from '../reactHelper';
@@ -12,8 +14,8 @@ const SelectField = ({
onChange,
endpoint,
data,
- keyGetter = item => item.id,
- titleGetter = item => item.name,
+ keyGetter = (item) => item.id,
+ titleGetter = (item) => item.name,
}) => {
const [items, setItems] = useState(data);
@@ -33,19 +35,18 @@ const SelectField = ({
<Select
multiple={multiple}
value={value}
- onChange={onChange}>
- {!multiple && emptyValue !== null &&
- <MenuItem value={emptyValue}>&nbsp;</MenuItem>
- }
- {items.map(item => (
+ onChange={onChange}
+ >
+ {!multiple && emptyValue !== null
+ && <MenuItem value={emptyValue}>&nbsp;</MenuItem>}
+ {items.map((item) => (
<MenuItem key={keyGetter(item)} value={keyGetter(item)}>{titleGetter(item)}</MenuItem>
))}
</Select>
</FormControl>
);
- } else {
- return null;
}
-}
+ return null;
+};
export default SelectField;
diff --git a/modern/src/index.js b/modern/src/index.js
index 82ddef9..155bf62 100644
--- a/modern/src/index.js
+++ b/modern/src/index.js
@@ -1,7 +1,7 @@
-import 'typeface-roboto'
+import 'typeface-roboto';
import React from 'react';
import ReactDOM from 'react-dom';
-import { HashRouter } from 'react-router-dom'
+import { HashRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import App from './App';
diff --git a/modern/src/map/AccuracyMap.js b/modern/src/map/AccuracyMap.js
index e81fc8f..4baa105 100644
--- a/modern/src/map/AccuracyMap.js
+++ b/modern/src/map/AccuracyMap.js
@@ -7,33 +7,31 @@ import { map } from './Map';
const AccuracyMap = () => {
const id = 'accuracy';
- const positions = useSelector(state => ({
+ const positions = useSelector((state) => ({
type: 'FeatureCollection',
- features: Object.values(state.positions.items).filter(position => position.accuracy > 0).map(position =>
- circle([position.longitude, position.latitude], position.accuracy * 0.001)
- ),
+ features: Object.values(state.positions.items).filter((position) => position.accuracy > 0).map((position) => circle([position.longitude, position.latitude], position.accuracy * 0.001)),
}));
useEffect(() => {
map.addSource(id, {
- 'type': 'geojson',
- 'data': {
+ type: 'geojson',
+ data: {
type: 'FeatureCollection',
- features: []
- }
+ features: [],
+ },
});
map.addLayer({
- 'source': id,
- 'id': id,
- 'type': 'fill',
- 'filter': [
- 'all',
- ['==', '$type', 'Polygon'],
+ source: id,
+ id,
+ type: 'fill',
+ filter: [
+ 'all',
+ ['==', '$type', 'Polygon'],
],
- 'paint': {
- 'fill-color':'#3bb2d0',
- 'fill-outline-color':'#3bb2d0',
- 'fill-opacity':0.25,
+ paint: {
+ 'fill-color': '#3bb2d0',
+ 'fill-outline-color': '#3bb2d0',
+ 'fill-opacity': 0.25,
},
});
@@ -48,6 +46,6 @@ const AccuracyMap = () => {
}, [positions]);
return null;
-}
+};
export default AccuracyMap;
diff --git a/modern/src/map/CurrentLocationMap.js b/modern/src/map/CurrentLocationMap.js
index 06aaad0..69724ce 100644
--- a/modern/src/map/CurrentLocationMap.js
+++ b/modern/src/map/CurrentLocationMap.js
@@ -16,6 +16,6 @@ const CurrentLocationMap = () => {
}, []);
return null;
-}
+};
export default CurrentLocationMap;
diff --git a/modern/src/map/CurrentPositionsMap.js b/modern/src/map/CurrentPositionsMap.js
index 0bfe4fc..9e00774 100644
--- a/modern/src/map/CurrentPositionsMap.js
+++ b/modern/src/map/CurrentPositionsMap.js
@@ -1,11 +1,11 @@
-import React, { } from 'react';
+import React, { } from 'react';
import { useSelector } from 'react-redux';
import PositionsMap from './PositionsMap';
const CurrentPositionsMap = () => {
- const positions = useSelector(state => Object.values(state.positions.items));
+ const positions = useSelector((state) => Object.values(state.positions.items));
return (<PositionsMap positions={positions} />);
-}
+};
export default CurrentPositionsMap;
diff --git a/modern/src/map/GeofenceEditMap.js b/modern/src/map/GeofenceEditMap.js
index fe84338..d639c19 100644
--- a/modern/src/map/GeofenceEditMap.js
+++ b/modern/src/map/GeofenceEditMap.js
@@ -1,13 +1,13 @@
-import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
+import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import theme from '@mapbox/mapbox-gl-draw/src/lib/theme';
import { useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { useHistory } from 'react-router-dom';
import { map } from './Map';
import { geofenceToFeature, geometryToArea } from './mapUtil';
-import { useDispatch, useSelector } from 'react-redux';
import { geofencesActions } from '../store';
-import { useHistory } from 'react-router-dom';
const draw = new MapboxDraw({
displayControlsDefault: false,
@@ -17,15 +17,15 @@ const draw = new MapboxDraw({
},
userProperties: true,
styles: [...theme, {
- 'id': 'gl-draw-title',
- 'type': 'symbol',
- 'filter': ['all'],
- 'layout': {
+ id: 'gl-draw-title',
+ type: 'symbol',
+ filter: ['all'],
+ layout: {
'text-field': '{user_name}',
'text-font': ['Roboto Regular'],
'text-size': 12,
},
- 'paint': {
+ paint: {
'text-halo-color': 'white',
'text-halo-width': 1,
},
@@ -36,25 +36,25 @@ const GeofenceEditMap = () => {
const dispatch = useDispatch();
const history = useHistory();
- const geofences = useSelector(state => Object.values(state.geofences.items));
+ const geofences = useSelector((state) => Object.values(state.geofences.items));
const refreshGeofences = async () => {
const response = await fetch('/api/geofences');
if (response.ok) {
dispatch(geofencesActions.refresh(await response.json()));
}
- }
+ };
useEffect(() => {
refreshGeofences();
map.addControl(draw, 'top-left');
- map.on('draw.create', async event => {
+ map.on('draw.create', async (event) => {
const feature = event.features[0];
const newItem = { name: '', area: geometryToArea(feature.geometry) };
draw.delete(feature.id);
- const response = await fetch(`/api/geofences`, {
+ const response = await fetch('/api/geofences', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newItem),
@@ -65,7 +65,7 @@ const GeofenceEditMap = () => {
}
});
- map.on('draw.delete', async event => {
+ map.on('draw.delete', async (event) => {
const feature = event.features[0];
const response = await fetch(`/api/geofences/${feature.id}`, { method: 'DELETE' });
if (response.ok) {
@@ -73,9 +73,9 @@ const GeofenceEditMap = () => {
}
});
- map.on('draw.update', async event => {
+ map.on('draw.update', async (event) => {
const feature = event.features[0];
- const item = geofences.find(i => i.id === feature.id);
+ const item = geofences.find((i) => i.id === feature.id);
if (item) {
const updatedItem = { ...item, area: geometryToArea(feature.geometry) };
const response = await fetch(`/api/geofences/${feature.id}`, {
@@ -94,12 +94,12 @@ const GeofenceEditMap = () => {
useEffect(() => {
draw.deleteAll();
- for (const geofence of geofences) {
+ geofences.forEach((geofence) => {
draw.add(geofenceToFeature(geofence));
- }
+ });
}, [geofences]);
return null;
-}
+};
export default GeofenceEditMap;
diff --git a/modern/src/map/GeofenceMap.js b/modern/src/map/GeofenceMap.js
index 8db175a..d00cbb1 100644
--- a/modern/src/map/GeofenceMap.js
+++ b/modern/src/map/GeofenceMap.js
@@ -7,49 +7,49 @@ import { geofenceToFeature } from './mapUtil';
const GeofenceMap = () => {
const id = 'geofences';
- const geofences = useSelector(state => Object.values(state.geofences.items));
+ const geofences = useSelector((state) => Object.values(state.geofences.items));
useEffect(() => {
map.addSource(id, {
- 'type': 'geojson',
- 'data': {
+ type: 'geojson',
+ data: {
type: 'FeatureCollection',
- features: []
- }
+ features: [],
+ },
});
map.addLayer({
- 'source': id,
- 'id': 'geofences-fill',
- 'type': 'fill',
- 'filter': [
- 'all',
- ['==', '$type', 'Polygon'],
+ source: id,
+ id: 'geofences-fill',
+ type: 'fill',
+ filter: [
+ 'all',
+ ['==', '$type', 'Polygon'],
],
- 'paint': {
- 'fill-color':'#3bb2d0',
- 'fill-outline-color':'#3bb2d0',
- 'fill-opacity':0.1,
+ paint: {
+ 'fill-color': '#3bb2d0',
+ 'fill-outline-color': '#3bb2d0',
+ 'fill-opacity': 0.1,
},
});
map.addLayer({
- 'source': id,
- 'id': 'geofences-line',
- 'type': 'line',
- 'paint': {
- 'line-color': '#3bb2d0',
- 'line-width': 2,
+ source: id,
+ id: 'geofences-line',
+ type: 'line',
+ paint: {
+ 'line-color': '#3bb2d0',
+ 'line-width': 2,
},
});
map.addLayer({
- 'source': id,
- 'id': 'geofences-title',
- 'type': 'symbol',
- 'layout': {
+ source: id,
+ id: 'geofences-title',
+ type: 'symbol',
+ layout: {
'text-field': '{name}',
'text-font': ['Roboto Regular'],
'text-size': 12,
},
- 'paint': {
+ paint: {
'text-halo-color': 'white',
'text-halo-width': 1,
},
@@ -66,11 +66,11 @@ const GeofenceMap = () => {
useEffect(() => {
map.getSource(id).setData({
type: 'FeatureCollection',
- features: geofences.map(geofenceToFeature)
+ features: geofences.map(geofenceToFeature),
});
}, [geofences]);
return null;
-}
+};
export default GeofenceMap;
diff --git a/modern/src/map/Map.js b/modern/src/map/Map.js
index 46c59d2..7dd1c2a 100644
--- a/modern/src/map/Map.js
+++ b/modern/src/map/Map.js
@@ -1,9 +1,11 @@
import 'maplibre-gl/dist/maplibre-gl.css';
import './switcher/switcher.css';
import maplibregl from 'maplibre-gl';
+import React, {
+ useRef, useLayoutEffect, useEffect, useState,
+} from 'react';
import { SwitcherControl } from './switcher/switcher';
-import React, { useRef, useLayoutEffect, useEffect, useState } from 'react';
-import { deviceCategories } from '../common/deviceCategories';
+import deviceCategories from '../common/deviceCategories';
import { prepareIcon, loadImage } from './mapUtil';
import { styleCarto, styleMapbox, styleOsm } from './mapStyles';
import t from '../common/localization';
@@ -22,18 +24,18 @@ export const map = new maplibregl.Map({
let ready = false;
const readyListeners = new Set();
-const addReadyListener = listener => {
+const addReadyListener = (listener) => {
readyListeners.add(listener);
listener(ready);
};
-const removeReadyListener = listener => {
+const removeReadyListener = (listener) => {
readyListeners.delete(listener);
};
-const updateReadyValue = value => {
+const updateReadyValue = (value) => {
ready = value;
- readyListeners.forEach(listener => listener(value));
+ readyListeners.forEach((listener) => listener(value));
};
const initMap = async () => {
@@ -42,13 +44,16 @@ const initMap = async () => {
map.addImage('background', await prepareIcon(background), {
pixelRatio: window.devicePixelRatio,
});
- await Promise.all(deviceCategories.map(async category => {
- for (const color of ['green', 'red', 'gray']) {
- const icon = await loadImage(`images/icon/${category}.svg`);
- map.addImage(`${category}-${color}`, prepareIcon(background, icon, palette.common[color]), {
- pixelRatio: window.devicePixelRatio,
- });
- }
+ await Promise.all(deviceCategories.map(async (category) => {
+ const results = [];
+ ['green', 'red', 'gray'].forEach((color) => {
+ results.push(loadImage(`images/icon/${category}.svg`).then((icon) => {
+ map.addImage(`${category}-${color}`, prepareIcon(background, icon, palette.common[color]), {
+ pixelRatio: window.devicePixelRatio,
+ });
+ }));
+ });
+ await Promise.all(results);
}));
updateReadyValue(true);
};
@@ -93,7 +98,7 @@ const Map = ({ children }) => {
}, [mapboxAccessToken]);
useEffect(() => {
- const listener = ready => setMapReady(ready);
+ const listener = (ready) => setMapReady(ready);
addReadyListener(listener);
return () => {
removeReadyListener(listener);
diff --git a/modern/src/map/PositionsMap.js b/modern/src/map/PositionsMap.js
index 35d6d92..2de01d2 100644
--- a/modern/src/map/PositionsMap.js
+++ b/modern/src/map/PositionsMap.js
@@ -3,9 +3,9 @@ import ReactDOM from 'react-dom';
import maplibregl from 'maplibre-gl';
import { Provider, useSelector } from 'react-redux';
+import { useHistory } from 'react-router-dom';
import { map } from './Map';
import store from '../store';
-import { useHistory } from 'react-router-dom';
import StatusView from './StatusView';
const PositionsMap = ({ positions }) => {
@@ -13,9 +13,9 @@ const PositionsMap = ({ positions }) => {
const clusters = `${id}-clusters`;
const history = useHistory();
- const devices = useSelector(state => state.devices.items);
+ const devices = useSelector((state) => state.devices.items);
- const deviceColor = device => {
+ const deviceColor = (device) => {
switch (device.status) {
case 'online':
return 'green';
@@ -33,15 +33,15 @@ const PositionsMap = ({ positions }) => {
name: device.name,
category: device.category || 'default',
color: deviceColor(device),
- }
+ };
};
const onMouseEnter = () => map.getCanvas().style.cursor = 'pointer';
const onMouseLeave = () => map.getCanvas().style.cursor = '';
- const onMarkerClick = useCallback(event => {
+ const onMarkerClick = useCallback((event) => {
const feature = event.features[0];
- let coordinates = feature.geometry.coordinates.slice();
+ const coordinates = feature.geometry.coordinates.slice();
while (Math.abs(event.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += event.lngLat.lng > coordinates[0] ? 360 : -360;
}
@@ -49,50 +49,52 @@ const PositionsMap = ({ positions }) => {
const placeholder = document.createElement('div');
ReactDOM.render(
<Provider store={store}>
- <StatusView deviceId={feature.properties.deviceId} onShowDetails={positionId => history.push(`/position/${positionId}`)} />
+ <StatusView deviceId={feature.properties.deviceId} onShowDetails={(positionId) => history.push(`/position/${positionId}`)} />
</Provider>,
- placeholder
+ placeholder,
);
new maplibregl.Popup({
offset: 25,
- anchor: 'top'
+ anchor: 'top',
})
.setDOMContent(placeholder)
.setLngLat(coordinates)
.addTo(map);
}, [history]);
- const onClusterClick = event => {
+ const onClusterClick = (event) => {
const features = map.queryRenderedFeatures(event.point, {
layers: [clusters],
});
const clusterId = features[0].properties.cluster_id;
map.getSource(id).getClusterExpansionZoom(clusterId, (error, zoom) => {
- if (!error) map.easeTo({
- center: features[0].geometry.coordinates,
- zoom: zoom,
- });
+ if (!error) {
+ map.easeTo({
+ center: features[0].geometry.coordinates,
+ zoom,
+ });
+ }
});
};
useEffect(() => {
map.addSource(id, {
- 'type': 'geojson',
- 'data': {
+ type: 'geojson',
+ data: {
type: 'FeatureCollection',
features: [],
},
- 'cluster': true,
- 'clusterMaxZoom': 14,
- 'clusterRadius': 50,
+ cluster: true,
+ clusterMaxZoom: 14,
+ clusterRadius: 50,
});
map.addLayer({
- 'id': id,
- 'type': 'symbol',
- 'source': id,
- 'filter': ['!', ['has', 'point_count']],
- 'layout': {
+ id,
+ type: 'symbol',
+ source: id,
+ filter: ['!', ['has', 'point_count']],
+ layout: {
'icon-image': '{category}-{color}',
'icon-allow-overlap': true,
'text-field': '{name}',
@@ -102,17 +104,17 @@ const PositionsMap = ({ positions }) => {
'text-font': ['Roboto Regular'],
'text-size': 12,
},
- 'paint': {
+ paint: {
'text-halo-color': 'white',
'text-halo-width': 1,
},
});
map.addLayer({
- 'id': clusters,
- 'type': 'symbol',
- 'source': id,
- 'filter': ['has', 'point_count'],
- 'layout': {
+ id: clusters,
+ type: 'symbol',
+ source: id,
+ filter: ['has', 'point_count'],
+ layout: {
'icon-image': 'background',
'text-field': '{point_count_abbreviated}',
'text-font': ['Roboto Regular'],
@@ -120,7 +122,6 @@ const PositionsMap = ({ positions }) => {
},
});
-
map.on('mouseenter', id, onMouseEnter);
map.on('mouseleave', id, onMouseLeave);
map.on('mouseenter', clusters, onMouseEnter);
@@ -129,7 +130,7 @@ const PositionsMap = ({ positions }) => {
map.on('click', clusters, onClusterClick);
return () => {
- Array.from(map.getContainer().getElementsByClassName('maplibregl-popup')).forEach(el => el.remove());
+ Array.from(map.getContainer().getElementsByClassName('maplibregl-popup')).forEach((el) => el.remove());
map.off('mouseenter', id, onMouseEnter);
map.off('mouseleave', id, onMouseLeave);
@@ -147,18 +148,18 @@ const PositionsMap = ({ positions }) => {
useEffect(() => {
map.getSource(id).setData({
type: 'FeatureCollection',
- features: positions.filter(it => devices.hasOwnProperty(it.deviceId)).map(position => ({
+ features: positions.filter((it) => devices.hasOwnProperty(it.deviceId)).map((position) => ({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [position.longitude, position.latitude],
},
properties: createFeature(devices, position),
- }))
+ })),
});
}, [devices, positions]);
return null;
-}
+};
export default PositionsMap;
diff --git a/modern/src/map/ReplayPathMap.js b/modern/src/map/ReplayPathMap.js
index b40aa69..62b3f27 100644
--- a/modern/src/map/ReplayPathMap.js
+++ b/modern/src/map/ReplayPathMap.js
@@ -7,8 +7,8 @@ const ReplayPathMap = ({ positions }) => {
useEffect(() => {
map.addSource(id, {
- 'type': 'geojson',
- 'data': {
+ type: 'geojson',
+ data: {
type: 'Feature',
geometry: {
type: 'LineString',
@@ -17,16 +17,16 @@ const ReplayPathMap = ({ positions }) => {
},
});
map.addLayer({
- 'source': id,
- 'id': id,
- 'type': 'line',
- 'layout': {
+ source: id,
+ id,
+ type: 'line',
+ layout: {
'line-join': 'round',
'line-cap': 'round',
},
- 'paint': {
- 'line-color': '#333',
- 'line-width': 5,
+ paint: {
+ 'line-color': '#333',
+ 'line-width': 5,
},
});
@@ -37,23 +37,25 @@ const ReplayPathMap = ({ positions }) => {
}, []);
useEffect(() => {
- const coordinates = positions.map(item => [item.longitude, item.latitude]);
+ const coordinates = positions.map((item) => [item.longitude, item.latitude]);
map.getSource(id).setData({
type: 'Feature',
geometry: {
type: 'LineString',
- coordinates: coordinates,
+ coordinates,
},
});
if (coordinates.length) {
const bounds = coordinates.reduce((bounds, item) => bounds.extend(item), new maplibregl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
- padding: { top: 50, bottom: 250, left: 25, right: 25 },
+ padding: {
+ top: 50, bottom: 250, left: 25, right: 25,
+ },
});
}
}, [positions]);
return null;
-}
+};
export default ReplayPathMap;
diff --git a/modern/src/map/SelectedDeviceMap.js b/modern/src/map/SelectedDeviceMap.js
index 655fca9..e6c5f58 100644
--- a/modern/src/map/SelectedDeviceMap.js
+++ b/modern/src/map/SelectedDeviceMap.js
@@ -4,7 +4,7 @@ import { useSelector } from 'react-redux';
import { map } from './Map';
const SelectedDeviceMap = () => {
- const mapCenter = useSelector(state => {
+ const mapCenter = useSelector((state) => {
if (state.devices.selectedId) {
const position = state.positions.items[state.devices.selectedId] || null;
if (position) {
@@ -19,6 +19,6 @@ const SelectedDeviceMap = () => {
}, [mapCenter]);
return null;
-}
+};
export default SelectedDeviceMap;
diff --git a/modern/src/map/StatusView.js b/modern/src/map/StatusView.js
index ae049af..20e5b74 100644
--- a/modern/src/map/StatusView.js
+++ b/modern/src/map/StatusView.js
@@ -1,27 +1,68 @@
-import t from '../common/localization'
import React from 'react';
import { useSelector } from 'react-redux';
+import t from '../common/localization';
import { formatPosition } from '../common/formatter';
const StatusView = ({ deviceId, onShowDetails }) => {
- const device = useSelector(state => state.devices.items[deviceId]);
- const position = useSelector(state => state.positions.items[deviceId]);
+ const device = useSelector((state) => state.devices.items[deviceId]);
+ const position = useSelector((state) => state.positions.items[deviceId]);
- const handleClick = e => {
+ const handleClick = (e) => {
e.preventDefault();
onShowDetails(position.id);
};
return (
<>
- <b>{t('deviceStatus')}:</b> {formatPosition(device.status, 'status')}<br />
- <b>{t('sharedLocation')}:</b> {formatPosition(position, 'latitude')} {formatPosition(position, 'longitude')}<br />
- <b>{t('positionSpeed')}:</b> {formatPosition(position.speed, 'speed')}<br />
- <b>{t('positionCourse')}:</b> {formatPosition(position.course, 'course')}<br />
- <b>{t('positionDistance')}:</b> {formatPosition(position.attributes.totalDistance, 'distance')}<br />
- {position.attributes.batteryLevel &&
- <><b>{t('positionBattery')}:</b> {formatPosition(position.attributes.batteryLevel, 'batteryLevel')}<br /></>
- }
+ <b>
+ {t('deviceStatus')}
+ :
+ </b>
+ {' '}
+ {formatPosition(device.status, 'status')}
+ <br />
+ <b>
+ {t('sharedLocation')}
+ :
+ </b>
+ {' '}
+ {formatPosition(position, 'latitude')}
+ {' '}
+ {formatPosition(position, 'longitude')}
+ <br />
+ <b>
+ {t('positionSpeed')}
+ :
+ </b>
+ {' '}
+ {formatPosition(position.speed, 'speed')}
+ <br />
+ <b>
+ {t('positionCourse')}
+ :
+ </b>
+ {' '}
+ {formatPosition(position.course, 'course')}
+ <br />
+ <b>
+ {t('positionDistance')}
+ :
+ </b>
+ {' '}
+ {formatPosition(position.attributes.totalDistance, 'distance')}
+ <br />
+ {position.attributes.batteryLevel
+ && (
+ <>
+ <b>
+ {t('positionBattery')}
+ :
+ </b>
+ {' '}
+ {formatPosition(position.attributes.batteryLevel, 'batteryLevel')}
+ <br />
+ </>
+ )}
<a href="/" onClick={handleClick}>{t('sharedShowDetails')}</a>
</>
);
diff --git a/modern/src/map/mapStyles.js b/modern/src/map/mapStyles.js
index 00a8666..9650ead 100644
--- a/modern/src/map/mapStyles.js
+++ b/modern/src/map/mapStyles.js
@@ -4,7 +4,7 @@ export const styleCustom = (url, attribution) => ({
osm: {
type: 'raster',
tiles: [url],
- attribution: attribution,
+ attribution,
tileSize: 256,
},
},
@@ -22,30 +22,30 @@ export const styleOsm = () => styleCustom(
);
export const styleCarto = () => ({
- 'version': 8,
- 'sources': {
+ version: 8,
+ sources: {
'raster-tiles': {
- 'type': 'raster',
- 'tiles': [
- 'https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
- 'https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
- 'https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
- 'https://d.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png'
+ type: 'raster',
+ tiles: [
+ 'https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
+ 'https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
+ 'https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
+ 'https://d.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
],
- 'tileSize': 256,
- 'attribution': 'Ā© <a target="_top" rel="noopener" href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Ā© <a target="_top" rel="noopener" href="https://carto.com/attribution">CARTO</a>'
- }
+ tileSize: 256,
+ attribution: 'Ā© <a target="_top" rel="noopener" href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Ā© <a target="_top" rel="noopener" href="https://carto.com/attribution">CARTO</a>',
+ },
},
- 'glyphs': 'https://cdn.traccar.com/map/fonts/{fontstack}/{range}.pbf',
- 'layers': [
+ glyphs: 'https://cdn.traccar.com/map/fonts/{fontstack}/{range}.pbf',
+ layers: [
{
- 'id': 'simple-tiles',
- 'type': 'raster',
- 'source': 'raster-tiles',
- 'minzoom': 0,
- 'maxzoom': 22,
- }
- ]
+ id: 'simple-tiles',
+ type: 'raster',
+ source: 'raster-tiles',
+ minzoom: 0,
+ maxzoom: 22,
+ },
+ ],
});
export const styleMapbox = (style) => `mapbox://styles/mapbox/${style}`;
diff --git a/modern/src/map/mapUtil.js b/modern/src/map/mapUtil.js
index 67ce345..e3c32f4 100644
--- a/modern/src/map/mapUtil.js
+++ b/modern/src/map/mapUtil.js
@@ -2,13 +2,11 @@ import { parse, stringify } from 'wellknown';
import canvasTintImage from 'canvas-tint-image';
import circle from '@turf/circle';
-export const loadImage = (url) => {
- return new Promise(imageLoaded => {
- const image = new Image();
- image.onload = () => imageLoaded(image);
- image.src = url;
- });
-};
+export const loadImage = (url) => new Promise((imageLoaded) => {
+ const image = new Image();
+ image.onload = () => imageLoaded(image);
+ image.src = url;
+});
export const prepareIcon = (background, icon, color) => {
const pixelRatio = window.devicePixelRatio;
@@ -32,44 +30,39 @@ export const prepareIcon = (background, icon, color) => {
return context.getImageData(0, 0, canvas.width, canvas.height);
};
-export const reverseCoordinates = it => {
+export const reverseCoordinates = (it) => {
if (!it) {
return it;
- } else if (Array.isArray(it)) {
+ } if (Array.isArray(it)) {
if (it.length === 2 && !Number.isNaN(it[0]) && !Number.isNaN(it[1])) {
return [it[1], it[0]];
- } else {
- return it.map(it => reverseCoordinates(it));
- }
- } else {
- return {
- ...it,
- coordinates: reverseCoordinates(it.coordinates),
}
+ return it.map((it) => reverseCoordinates(it));
}
-}
+ return {
+ ...it,
+ coordinates: reverseCoordinates(it.coordinates),
+ };
+};
export const geofenceToFeature = (item) => {
if (item.area.indexOf('CIRCLE') > -1) {
- let coordinates = item.area.replace(/CIRCLE|\(|\)|,/g, " ").trim().split(/ +/);
- var options = { steps: 32, units: 'meters' };
- let polygon = circle([Number(coordinates[1]), Number(coordinates[0])], Number(coordinates[2]), options);
+ const coordinates = item.area.replace(/CIRCLE|\(|\)|,/g, ' ').trim().split(/ +/);
+ const options = { steps: 32, units: 'meters' };
+ const polygon = circle([Number(coordinates[1]), Number(coordinates[0])], Number(coordinates[2]), options);
return {
id: item.id,
type: 'Feature',
geometry: polygon.geometry,
- properties: { name: item.name }
- };
- } else {
- return {
- id: item.id,
- type: 'Feature',
- geometry: reverseCoordinates(parse(item.area)),
- properties: { name: item.name }
+ properties: { name: item.name },
};
}
-}
+ return {
+ id: item.id,
+ type: 'Feature',
+ geometry: reverseCoordinates(parse(item.area)),
+ properties: { name: item.name },
+ };
+};
-export const geometryToArea = (geometry) => {
- return stringify(reverseCoordinates(geometry));
-}
+export const geometryToArea = (geometry) => stringify(reverseCoordinates(geometry));
diff --git a/modern/src/map/switcher/switcher.js b/modern/src/map/switcher/switcher.js
index a755645..e9076aa 100644
--- a/modern/src/map/switcher/switcher.js
+++ b/modern/src/map/switcher/switcher.js
@@ -1,5 +1,4 @@
export class SwitcherControl {
-
constructor(styles, defaultStyle, beforeSwitch, afterSwitch) {
this.styles = styles;
this.defaultStyle = defaultStyle;
@@ -27,8 +26,8 @@ export class SwitcherControl {
styleElement.innerText = style.title;
styleElement.classList.add(style.title.replace(/[^a-z0-9-]/gi, '_'));
styleElement.dataset.uri = JSON.stringify(style.uri);
- styleElement.addEventListener('click', event => {
- const srcElement = event.srcElement;
+ styleElement.addEventListener('click', (event) => {
+ const { srcElement } = event;
if (srcElement.classList.contains('active')) {
return;
}
diff --git a/modern/src/reactHelper.js b/modern/src/reactHelper.js
index b0eb016..f3ef78d 100644
--- a/modern/src/reactHelper.js
+++ b/modern/src/reactHelper.js
@@ -1,7 +1,6 @@
-
import { useRef, useEffect } from 'react';
-export const usePrevious = value => {
+export const usePrevious = (value) => {
const ref = useRef();
useEffect(() => {
ref.current = value;
@@ -12,5 +11,5 @@ export const usePrevious = value => {
export const useEffectAsync = (effect, deps) => {
useEffect(() => {
effect();
- }, deps); // eslint-disable-line react-hooks/exhaustive-deps
+ }, deps);
};
diff --git a/modern/src/reports/ChartReportPage.js b/modern/src/reports/ChartReportPage.js
index 0a5c8e1..70ce780 100644
--- a/modern/src/reports/ChartReportPage.js
+++ b/modern/src/reports/ChartReportPage.js
@@ -1,5 +1,7 @@
import React, { useState } from 'react';
-import { Grid, FormControl, InputLabel, Select, MenuItem } from '@material-ui/core';
+import {
+ Grid, FormControl, InputLabel, Select, MenuItem,
+} from '@material-ui/core';
import ReportLayoutPage from './ReportLayoutPage';
import ReportFilter from './ReportFilter';
import Graph from './Graph';
@@ -9,66 +11,61 @@ import { speedFromKnots } from '../common/converter';
import t from '../common/localization';
const Filter = ({ children, setItems }) => {
-
const speedUnit = useAttributePreference('speedUnit');
const handleSubmit = async (deviceId, from, to, mail, headers) => {
- const query = new URLSearchParams({ deviceId, from, to, mail });
+ const query = new URLSearchParams({
+ deviceId, from, to, mail,
+ });
const response = await fetch(`/api/reports/route?${query.toString()}`, { headers });
if (response.ok) {
const positions = await response.json();
- let formattedPositions = positions.map(position => {
- return {
- speed: Number(speedFromKnots(position.speed, speedUnit)),
- altitude: position.altitude,
- accuracy: position.accuracy,
- fixTime: formatDate(position.fixTime)
- }
- });
+ const formattedPositions = positions.map((position) => ({
+ speed: Number(speedFromKnots(position.speed, speedUnit)),
+ altitude: position.altitude,
+ accuracy: position.accuracy,
+ fixTime: formatDate(position.fixTime),
+ }));
setItems(formattedPositions);
}
- }
+ };
return (
<>
<ReportFilter handleSubmit={handleSubmit} showOnly />
{children}
</>
- )
-}
-
-const ChartType = ({ type, setType }) => {
+ );
+};
- return (
- <Grid container spacing={3}>
- <Grid item xs={12} sm={6}>
- <FormControl variant="filled" margin="normal" fullWidth>
- <InputLabel>{t('reportChartType')}</InputLabel>
- <Select value={type} onChange={e => setType(e.target.value)}>
- <MenuItem value="speed">{t('positionSpeed')}</MenuItem>
- <MenuItem value="accuracy">{t('positionAccuracy')}</MenuItem>
- <MenuItem value="altitude">{t('positionAltitude')}</MenuItem>
- </Select>
- </FormControl>
- </Grid>
+const ChartType = ({ type, setType }) => (
+ <Grid container spacing={3}>
+ <Grid item xs={12} sm={6}>
+ <FormControl variant="filled" margin="normal" fullWidth>
+ <InputLabel>{t('reportChartType')}</InputLabel>
+ <Select value={type} onChange={(e) => setType(e.target.value)}>
+ <MenuItem value="speed">{t('positionSpeed')}</MenuItem>
+ <MenuItem value="accuracy">{t('positionAccuracy')}</MenuItem>
+ <MenuItem value="altitude">{t('positionAltitude')}</MenuItem>
+ </Select>
+ </FormControl>
</Grid>
- )
-}
-
+ </Grid>
+);
const ChartReportPage = () => {
-
const [items, setItems] = useState([]);
const [type, setType] = useState('speed');
return (
- <ReportLayoutPage filter={
+ <ReportLayoutPage filter={(
<Filter setItems={setItems}>
<ChartType type={type} setType={setType} />
</Filter>
- }>
+ )}
+ >
<Graph items={items} type={type} />
</ReportLayoutPage>
- )
-}
+ );
+};
export default ChartReportPage;
diff --git a/modern/src/reports/EventReportPage.js b/modern/src/reports/EventReportPage.js
index 6d80860..89efcf7 100644
--- a/modern/src/reports/EventReportPage.js
+++ b/modern/src/reports/EventReportPage.js
@@ -1,7 +1,9 @@
import React, { useState } from 'react';
import { DataGrid } from '@material-ui/data-grid';
-import { Grid, FormControl, InputLabel, Select, MenuItem } from '@material-ui/core';
-import { useTheme } from "@material-ui/core/styles";
+import {
+ Grid, FormControl, InputLabel, Select, MenuItem,
+} from '@material-ui/core';
+import { useTheme } from '@material-ui/core/styles';
import { useSelector } from 'react-redux';
import { formatDate } from '../common/formatter';
import ReportFilter from './ReportFilter';
@@ -10,12 +12,13 @@ import { prefixString } from '../common/stringUtils';
import t from '../common/localization';
const Filter = ({ setItems }) => {
-
const [eventTypes, setEventTypes] = useState(['allEvents']);
const handleSubmit = async (deviceId, from, to, mail, headers) => {
- const query = new URLSearchParams({ deviceId, from, to, mail });
- eventTypes.forEach(it => query.append('type', it));
+ const query = new URLSearchParams({
+ deviceId, from, to, mail,
+ });
+ eventTypes.forEach((it) => query.append('type', it));
const response = await fetch(`/api/reports/events?${query.toString()}`, { headers });
if (response.ok) {
const contentType = response.headers.get('content-type');
@@ -34,7 +37,7 @@ const Filter = ({ setItems }) => {
<Grid item xs={12} sm={6}>
<FormControl variant="filled" fullWidth>
<InputLabel>{t('reportEventTypes')}</InputLabel>
- <Select value={eventTypes} onChange={e => setEventTypes(e.target.value)} multiple>
+ <Select value={eventTypes} onChange={(e) => setEventTypes(e.target.value)} multiple>
<MenuItem value="allEvents">{t('eventAll')}</MenuItem>
<MenuItem value="deviceOnline">{t('eventDeviceOnline')}</MenuItem>
<MenuItem value="deviceUnknown">{t('eventDeviceUnknown')}</MenuItem>
@@ -58,21 +61,20 @@ const Filter = ({ setItems }) => {
</Grid>
</ReportFilter>
);
-}
+};
const EventReportPage = () => {
-
const theme = useTheme();
- const geofences = useSelector(state => state.geofences.items);
+ const geofences = useSelector((state) => state.geofences.items);
const [items, setItems] = useState([]);
- const formatGeofence = value => {
+ const formatGeofence = (value) => {
if (value > 0) {
- const geofence = geofences[value];
- return geofence ? geofence.name : '';
+ const geofence = geofences[value];
+ return geofence ? geofence.name : '';
}
return null;
- }
+ };
const columns = [{
headerName: t('positionFixTime'),
@@ -101,12 +103,13 @@ const EventReportPage = () => {
return (
<ReportLayoutPage filter={<Filter setItems={setItems} />}>
<DataGrid
- rows={items}
- columns={columns}
- hideFooter
- autoHeight />
+ rows={items}
+ columns={columns}
+ hideFooter
+ autoHeight
+ />
</ReportLayoutPage>
);
-}
+};
export default EventReportPage;
diff --git a/modern/src/reports/Graph.js b/modern/src/reports/Graph.js
index 990eb5d..63d24ee 100644
--- a/modern/src/reports/Graph.js
+++ b/modern/src/reports/Graph.js
@@ -1,9 +1,11 @@
import React from 'react';
import { withWidth } from '@material-ui/core';
-import {LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
+import {
+ LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer,
+} from 'recharts';
-const CustomizedAxisTick = ({ x, y, payload }) =>{
- if(!payload.value) {
+const CustomizedAxisTick = ({ x, y, payload }) => {
+ if (!payload.value) {
return payload.value;
}
const parts = payload.value.split(' ');
@@ -13,22 +15,19 @@ const CustomizedAxisTick = ({ x, y, payload }) =>{
<text x={0} y={16} dy={16} textAnchor="end" fill="#666" transform="rotate(-35)">{parts[1]}</text>
</g>
);
-}
+};
-const Graph = ({ type, items }) => {
-
- return (
- <ResponsiveContainer height={400} width="100%" debounce={1}>
- <LineChart data={items}>
- <XAxis dataKey="fixTime" tick={<CustomizedAxisTick/>} height={60} />
- <YAxis />
- <CartesianGrid strokeDasharray="3 3" />
- <Tooltip />
- <Legend />
- <Line type="natural" dataKey={type} />
- </LineChart>
- </ResponsiveContainer>
- );
-}
+const Graph = ({ type, items }) => (
+ <ResponsiveContainer height={400} width="100%" debounce={1}>
+ <LineChart data={items}>
+ <XAxis dataKey="fixTime" tick={<CustomizedAxisTick />} height={60} />
+ <YAxis />
+ <CartesianGrid strokeDasharray="3 3" />
+ <Tooltip />
+ <Legend />
+ <Line type="natural" dataKey={type} />
+ </LineChart>
+ </ResponsiveContainer>
+);
export default withWidth()(Graph);
diff --git a/modern/src/reports/ReplayPage.js b/modern/src/reports/ReplayPage.js
index dfa9999..12bbd35 100644
--- a/modern/src/reports/ReplayPage.js
+++ b/modern/src/reports/ReplayPage.js
@@ -1,5 +1,7 @@
import React, { useState } from 'react';
-import { Accordion, AccordionDetails, AccordionSummary, Container, makeStyles, Paper, Slider, Tooltip, Typography } from '@material-ui/core';
+import {
+ Accordion, AccordionDetails, AccordionSummary, Container, makeStyles, Paper, Slider, Tooltip, Typography,
+} from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import MainToolbar from '../MainToolbar';
import Map from '../map/Map';
@@ -9,7 +11,7 @@ import PositionsMap from '../map/PositionsMap';
import { formatPosition } from '../common/formatter';
import ReportFilter from './ReportFilter';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
height: '100%',
display: 'flex',
@@ -31,13 +33,11 @@ const useStyles = makeStyles(theme => ({
},
}));
-const TimeLabel = ({ children, open, value }) => {
- return (
- <Tooltip open={open} enterTouchDelay={0} placement="top" title={value}>
- {children}
- </Tooltip>
- );
-};
+const TimeLabel = ({ children, open, value }) => (
+ <Tooltip open={open} enterTouchDelay={0} placement="top" title={value}>
+ {children}
+ </Tooltip>
+);
const ReplayPage = () => {
const classes = useStyles();
@@ -61,12 +61,12 @@ const ReplayPage = () => {
<MainToolbar />
<Map>
<ReplayPathMap positions={positions} />
- {index < positions.length &&
- <PositionsMap positions={[positions[index]]} />
- }
+ {index < positions.length
+ && <PositionsMap positions={[positions[index]]} />}
</Map>
<Container maxWidth="sm" className={classes.controlPanel}>
- {!!positions.length &&
+ {!!positions.length
+ && (
<Paper className={classes.controlContent}>
<Slider
max={positions.length - 1}
@@ -75,15 +75,15 @@ const ReplayPage = () => {
value={index}
onChange={(_, index) => setIndex(index)}
valueLabelDisplay="auto"
- valueLabelFormat={i => i < positions.length ? formatPosition(positions[i], 'fixTime') : ''}
+ valueLabelFormat={(i) => (i < positions.length ? formatPosition(positions[i], 'fixTime') : '')}
ValueLabelComponent={TimeLabel}
- />
+ />
</Paper>
- }
+ )}
<div>
<Accordion expanded={expanded} onChange={() => setExpanded(!expanded)}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
- <Typography align='center'>
+ <Typography align="center">
{t('reportConfigure')}
</Typography>
</AccordionSummary>
@@ -95,6 +95,6 @@ const ReplayPage = () => {
</Container>
</div>
);
-}
+};
export default ReplayPage;
diff --git a/modern/src/reports/ReportFilter.js b/modern/src/reports/ReportFilter.js
index c92741e..1e2eb88 100644
--- a/modern/src/reports/ReportFilter.js
+++ b/modern/src/reports/ReportFilter.js
@@ -1,11 +1,13 @@
import React, { useState } from 'react';
-import { FormControl, InputLabel, Select, MenuItem, Button, TextField, Grid, Typography } from '@material-ui/core';
+import {
+ FormControl, InputLabel, Select, MenuItem, Button, TextField, Grid, Typography,
+} from '@material-ui/core';
import { useSelector } from 'react-redux';
import moment from 'moment';
import t from '../common/localization';
const ReportFilter = ({ children, handleSubmit, showOnly }) => {
- const devices = useSelector(state => Object.values(state.devices.items));
+ const devices = useSelector((state) => Object.values(state.devices.items));
const [deviceId, setDeviceId] = useState();
const [period, setPeriod] = useState('today');
const [from, setFrom] = useState(moment().subtract(1, 'hour'));
@@ -51,9 +53,9 @@ const ReportFilter = ({ children, handleSubmit, showOnly }) => {
selectedFrom.toISOString(),
selectedTo.toISOString(),
mail,
- { Accept: accept }
+ { Accept: accept },
);
- }
+ };
return (
<Grid container spacing={2}>
@@ -81,56 +83,69 @@ const ReportFilter = ({ children, handleSubmit, showOnly }) => {
</Select>
</FormControl>
</Grid>
- {period === 'custom' && <Grid item xs={12} sm={3}>
+ {period === 'custom' && (
+ <Grid item xs={12} sm={3}>
<TextField
variant="filled"
label={t('reportFrom')}
type="datetime-local"
value={from.format(moment.HTML5_FMT.DATETIME_LOCAL)}
- onChange={e => setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
- fullWidth />
- </Grid>}
- {period === 'custom' && <Grid item xs={12} sm={3}>
+ onChange={(e) => setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
+ fullWidth
+ />
+ </Grid>
+ )}
+ {period === 'custom' && (
+ <Grid item xs={12} sm={3}>
<TextField
variant="filled"
label={t('reportTo')}
type="datetime-local"
value={to.format(moment.HTML5_FMT.DATETIME_LOCAL)}
- onChange={e => setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
- fullWidth />
- </Grid>}
+ onChange={(e) => setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
+ fullWidth
+ />
+ </Grid>
+ )}
{children}
<Grid item xs={!showOnly ? 4 : 12} sm={!showOnly ? 2 : 6}>
- <Button
+ <Button
onClick={() => handleClick(false, true)}
- variant='outlined'
- color='secondary'
- fullWidth>
+ variant="outlined"
+ color="secondary"
+ fullWidth
+ >
{t('reportShow')}
</Button>
</Grid>
- {!showOnly &&
+ {!showOnly
+ && (
<Grid item xs={4} sm={2}>
- <Button
- onClick={() => handleClick(false, false)}
- variant='outlined'
- color='secondary'
- fullWidth>
- {t('reportExport')}
- </Button>
- </Grid>}
- {!showOnly &&
+ <Button
+ onClick={() => handleClick(false, false)}
+ variant="outlined"
+ color="secondary"
+ fullWidth
+ >
+ {t('reportExport')}
+ </Button>
+ </Grid>
+ )}
+ {!showOnly
+ && (
<Grid item xs={4} sm={2}>
- <Button
- onClick={() => handleClick(true, false)}
- variant='outlined'
- color='secondary'
- fullWidth>
- <Typography variant="button" noWrap>{t('reportEmail')}</Typography>
- </Button>
- </Grid>}
+ <Button
+ onClick={() => handleClick(true, false)}
+ variant="outlined"
+ color="secondary"
+ fullWidth
+ >
+ <Typography variant="button" noWrap>{t('reportEmail')}</Typography>
+ </Button>
+ </Grid>
+ )}
</Grid>
);
-}
+};
export default ReportFilter;
diff --git a/modern/src/reports/ReportLayoutPage.js b/modern/src/reports/ReportLayoutPage.js
index 6bab67c..d25a887 100644
--- a/modern/src/reports/ReportLayoutPage.js
+++ b/modern/src/reports/ReportLayoutPage.js
@@ -1,6 +1,8 @@
import React, { useState, useEffect } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
-import { Grid, Typography, Divider, Drawer, makeStyles, IconButton, Hidden } from '@material-ui/core';
+import {
+ Grid, Typography, Divider, Drawer, makeStyles, IconButton, Hidden,
+} from '@material-ui/core';
import TimelineIcon from '@material-ui/icons/Timeline';
import PauseCircleFilledIcon from '@material-ui/icons/PauseCircleFilled';
import PlayCircleFilledIcon from '@material-ui/icons/PlayCircleFilled';
@@ -9,11 +11,11 @@ import FormatListBulletedIcon from '@material-ui/icons/FormatListBulleted';
import TrendingUpIcon from '@material-ui/icons/TrendingUp';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
-import ReportSidebar from '../components/reports/ReportSidebar'
-import ReportNavbar from '../components/reports/ReportNavbar'
+import ReportSidebar from '../components/reports/ReportSidebar';
+import ReportNavbar from '../components/reports/ReportNavbar';
import t from '../common/localization';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
height: '100%',
@@ -23,10 +25,10 @@ const useStyles = makeStyles(theme => ({
},
drawer: {
width: theme.dimensions.drawerWidthDesktop,
- [theme.breakpoints.down("md")]: {
+ [theme.breakpoints.down('md')]: {
width: theme.dimensions.drawerWidthTablet,
- }
- },
+ },
+ },
content: {
flex: 1,
padding: theme.spacing(5, 3, 3, 3),
@@ -39,13 +41,13 @@ const useStyles = makeStyles(theme => ({
},
backArrowIconContainer: {
'&:hover': {
- backgroundColor:"transparent"
- }
+ backgroundColor: 'transparent',
+ },
},
toolbar: {
- [theme.breakpoints.down("md")]: {
+ [theme.breakpoints.down('md')]: {
...theme.mixins.toolbar,
- }
+ },
},
}));
@@ -58,7 +60,7 @@ const routes = [
{ name: t('reportChart'), href: '/reports/chart', icon: <TrendingUpIcon /> },
];
-const ReportLayoutPage = ({ children, filter, }) => {
+const ReportLayoutPage = ({ children, filter }) => {
const classes = useStyles();
const history = useHistory();
const location = useLocation();
@@ -66,7 +68,7 @@ const ReportLayoutPage = ({ children, filter, }) => {
const [reportTitle, setReportTitle] = useState();
useEffect(() => {
- routes.forEach(route => {
+ routes.forEach((route) => {
switch (location.pathname) {
case `${route.href}`:
setReportTitle(route.name);
@@ -85,7 +87,8 @@ const ReportLayoutPage = ({ children, filter, }) => {
variant="temporary"
open={openDrawer}
onClose={() => setOpenDrawer(!openDrawer)}
- classes={{paper: classes.drawer}}>
+ classes={{ paper: classes.drawer }}
+ >
<ReportSidebar routes={routes} />
</Drawer>
</Hidden>
@@ -93,17 +96,19 @@ const ReportLayoutPage = ({ children, filter, }) => {
<div className={classes.drawerContainer}>
<Drawer
variant="permanent"
- classes={{paper: classes.drawer}}>
+ classes={{ paper: classes.drawer }}
+ >
<div className={classes.drawerHeader}>
<IconButton
onClick={() => history.push('/')}
- className={classes.backArrowIconContainer}
- disableRipple>
+ className={classes.backArrowIconContainer}
+ disableRipple
+ >
<ArrowBackIcon />
</IconButton>
<Typography variant="h6" color="inherit" noWrap>
{t('reportTitle')}
- </Typography>
+ </Typography>
</div>
<Divider />
<ReportSidebar routes={routes} />
@@ -116,9 +121,9 @@ const ReportLayoutPage = ({ children, filter, }) => {
<Grid item>{filter}</Grid>
<Grid item>{children}</Grid>
</Grid>
- </div>
+ </div>
</div>
);
-}
+};
export default ReportLayoutPage;
diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js
index 04b513e..dce08cb 100644
--- a/modern/src/reports/RouteReportPage.js
+++ b/modern/src/reports/RouteReportPage.js
@@ -1,17 +1,20 @@
import React, { useState } from 'react';
import { Paper } from '@material-ui/core';
import { DataGrid } from '@material-ui/data-grid';
-import { useTheme } from "@material-ui/core/styles";
-import { formatDistance, formatSpeed, formatBoolean, formatDate, formatCoordinate } from '../common/formatter';
+import { useTheme } from '@material-ui/core/styles';
+import {
+ formatDistance, formatSpeed, formatBoolean, formatDate, formatCoordinate,
+} from '../common/formatter';
import ReportFilter from './ReportFilter';
import ReportLayoutPage from './ReportLayoutPage';
import { useAttributePreference, usePreference } from '../common/preferences';
import t from '../common/localization';
const Filter = ({ setItems }) => {
-
const handleSubmit = async (deviceId, from, to, mail, headers) => {
- const query = new URLSearchParams({ deviceId, from, to, mail });
+ const query = new URLSearchParams({
+ deviceId, from, to, mail,
+ });
const response = await fetch(`/api/reports/route?${query.toString()}`, { headers });
if (response.ok) {
const contentType = response.headers.get('content-type');
@@ -23,7 +26,7 @@ const Filter = ({ setItems }) => {
}
}
}
- }
+ };
return <ReportFilter handleSubmit={handleSubmit} />;
};
@@ -78,7 +81,7 @@ const RouteReportPage = () => {
width: theme.dimensions.columnWidthNumber,
valueGetter: ({ row }) => row.attributes.totalDistance,
valueFormatter: ({ value }) => formatDistance(value, distanceUnit),
- }]
+ }];
const [items, setItems] = useState([]);
@@ -86,10 +89,11 @@ const RouteReportPage = () => {
<ReportLayoutPage filter={<Filter setItems={setItems} />}>
<Paper>
<DataGrid
- rows={items}
- columns={columns}
- hideFooter
- autoHeight />
+ rows={items}
+ columns={columns}
+ hideFooter
+ autoHeight
+ />
</Paper>
</ReportLayoutPage>
);
diff --git a/modern/src/reports/StopReportPage.js b/modern/src/reports/StopReportPage.js
index 6953c46..078a5e5 100644
--- a/modern/src/reports/StopReportPage.js
+++ b/modern/src/reports/StopReportPage.js
@@ -1,16 +1,19 @@
import React, { useState } from 'react';
import { DataGrid } from '@material-ui/data-grid';
-import { useTheme } from "@material-ui/core/styles";
-import { formatDistance, formatHours, formatDate, formatVolume } from '../common/formatter';
+import { useTheme } from '@material-ui/core/styles';
+import {
+ formatDistance, formatHours, formatDate, formatVolume,
+} from '../common/formatter';
import ReportFilter from './ReportFilter';
import ReportLayoutPage from './ReportLayoutPage';
import { useAttributePreference } from '../common/preferences';
import t from '../common/localization';
const Filter = ({ setItems }) => {
-
const handleSubmit = async (deviceId, from, to, mail, headers) => {
- const query = new URLSearchParams({ deviceId, from, to, mail });
+ const query = new URLSearchParams({
+ deviceId, from, to, mail,
+ });
const response = await fetch(`/api/reports/stops?${query.toString()}`, { headers });
if (response.ok) {
const contentType = response.headers.get('content-type');
@@ -22,13 +25,12 @@ const Filter = ({ setItems }) => {
}
}
}
- }
+ };
return <ReportFilter handleSubmit={handleSubmit} />;
};
const StopReportPage = () => {
-
const theme = useTheme();
const distanceUnit = useAttributePreference('distanceUnit');
@@ -41,7 +43,7 @@ const StopReportPage = () => {
field: 'startTime',
type: 'dateTime',
width: theme.dimensions.columnWidthDate,
- valueFormatter: ({ value }) => formatDate(value),
+ valueFormatter: ({ value }) => formatDate(value),
}, {
headerName: t('positionOdometer'),
field: 'startOdometer',
@@ -53,7 +55,7 @@ const StopReportPage = () => {
field: 'address',
type: 'string',
hide: true,
- width: theme.dimensions.columnWidthString,
+ width: theme.dimensions.columnWidthString,
}, {
headerName: t('reportEndTime'),
field: 'endTime',
@@ -78,17 +80,18 @@ const StopReportPage = () => {
type: 'number',
width: theme.dimensions.columnWidthNumber,
hide: true,
- valueFormatter: ({ value }) => formatVolume(value, volumeUnit),
- }]
-
+ valueFormatter: ({ value }) => formatVolume(value, volumeUnit),
+ }];
+
return (
<ReportLayoutPage filter={<Filter setItems={setItems} />}>
<DataGrid
- rows={items}
- columns={columns}
- hideFooter
+ rows={items}
+ columns={columns}
+ hideFooter
autoHeight
- getRowId={() => Math.random()} />
+ getRowId={() => Math.random()}
+ />
</ReportLayoutPage>
);
};
diff --git a/modern/src/reports/SummaryReportPage.js b/modern/src/reports/SummaryReportPage.js
index e3819a5..0e88705 100644
--- a/modern/src/reports/SummaryReportPage.js
+++ b/modern/src/reports/SummaryReportPage.js
@@ -1,19 +1,22 @@
import React, { useState } from 'react';
import { DataGrid } from '@material-ui/data-grid';
import { Grid, FormControlLabel, Checkbox } from '@material-ui/core';
-import { useTheme } from "@material-ui/core/styles";
-import { formatDistance, formatHours, formatDate, formatSpeed, formatVolume } from '../common/formatter';
+import { useTheme } from '@material-ui/core/styles';
+import {
+ formatDistance, formatHours, formatDate, formatSpeed, formatVolume,
+} from '../common/formatter';
import ReportFilter from './ReportFilter';
import ReportLayoutPage from './ReportLayoutPage';
import { useAttributePreference } from '../common/preferences';
import t from '../common/localization';
const Filter = ({ setItems }) => {
-
const [daily, setDaily] = useState(false);
const handleSubmit = async (deviceId, from, to, mail, headers) => {
- const query = new URLSearchParams({ deviceId, from, to, daily, mail });
+ const query = new URLSearchParams({
+ deviceId, from, to, daily, mail,
+ });
const response = await fetch(`/api/reports/summary?${query.toString()}`, { headers });
if (response.ok) {
const contentType = response.headers.get('content-type');
@@ -25,21 +28,21 @@ const Filter = ({ setItems }) => {
}
}
}
- }
+ };
return (
<ReportFilter handleSubmit={handleSubmit}>
<Grid item xs={12} sm={6}>
<FormControlLabel
- control={<Checkbox checked={daily} onChange={e => setDaily(e.target.checked)} />}
- label={t('reportDaily')} />
+ control={<Checkbox checked={daily} onChange={(e) => setDaily(e.target.checked)} />}
+ label={t('reportDaily')}
+ />
</Grid>
</ReportFilter>
);
-}
+};
const SummaryReportPage = () => {
-
const theme = useTheme();
const distanceUnit = useAttributePreference('distanceUnit');
@@ -96,19 +99,20 @@ const SummaryReportPage = () => {
type: 'number',
width: theme.dimensions.columnWidthNumber,
hide: true,
- valueFormatter: ({ value }) => formatVolume(value, volumeUnit),
- }]
-
+ valueFormatter: ({ value }) => formatVolume(value, volumeUnit),
+ }];
+
return (
<ReportLayoutPage filter={<Filter setItems={setItems} />}>
<DataGrid
- rows={items}
- columns={columns}
- hideFooter
+ rows={items}
+ columns={columns}
+ hideFooter
autoHeight
- getRowId={() => Math.random()} />
+ getRowId={() => Math.random()}
+ />
</ReportLayoutPage>
);
-}
+};
export default SummaryReportPage;
diff --git a/modern/src/reports/TripReportPage.js b/modern/src/reports/TripReportPage.js
index 5f414f4..c10e6b1 100644
--- a/modern/src/reports/TripReportPage.js
+++ b/modern/src/reports/TripReportPage.js
@@ -1,16 +1,19 @@
import React, { useState } from 'react';
import { DataGrid } from '@material-ui/data-grid';
-import { useTheme } from "@material-ui/core/styles";
-import { formatDistance, formatSpeed, formatHours, formatDate, formatVolume } from '../common/formatter';
+import { useTheme } from '@material-ui/core/styles';
+import {
+ formatDistance, formatSpeed, formatHours, formatDate, formatVolume,
+} from '../common/formatter';
import ReportFilter from './ReportFilter';
import ReportLayoutPage from './ReportLayoutPage';
import { useAttributePreference } from '../common/preferences';
import t from '../common/localization';
const Filter = ({ setItems }) => {
-
const handleSubmit = async (deviceId, from, to, mail, headers) => {
- const query = new URLSearchParams({ deviceId, from, to, mail });
+ const query = new URLSearchParams({
+ deviceId, from, to, mail,
+ });
const response = await fetch(`/api/reports/trips?${query.toString()}`, { headers });
if (response.ok) {
const contentType = response.headers.get('content-type');
@@ -22,15 +25,14 @@ const Filter = ({ setItems }) => {
}
}
}
- }
+ };
return <ReportFilter handleSubmit={handleSubmit} />;
-}
+};
const TripReportPage = () => {
-
const theme = useTheme();
-
+
const distanceUnit = useAttributePreference('distanceUnit');
const speedUnit = useAttributePreference('speedUnit');
const volumeUnit = useAttributePreference('volumeUnit');
@@ -109,19 +111,20 @@ const TripReportPage = () => {
field: 'driverName',
type: 'string',
width: theme.dimensions.columnWidthString,
- hide: true
- }]
+ hide: true,
+ }];
return (
<ReportLayoutPage filter={<Filter setItems={setItems} />}>
<DataGrid
- rows={items}
- columns={columns}
- hideFooter
+ rows={items}
+ columns={columns}
+ hideFooter
autoHeight
- getRowId={() => Math.random()} />
+ getRowId={() => Math.random()}
+ />
</ReportLayoutPage>
);
-}
+};
export default TripReportPage;
diff --git a/modern/src/serviceWorker.js b/modern/src/serviceWorker.js
index f59f199..a034430 100644
--- a/modern/src/serviceWorker.js
+++ b/modern/src/serviceWorker.js
@@ -11,13 +11,13 @@
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
- window.location.hostname === 'localhost' ||
+ window.location.hostname === 'localhost'
// [::1] is the IPv6 localhost address.
- window.location.hostname === '[::1]' ||
+ || window.location.hostname === '[::1]'
// 127.0.0.0/8 are considered localhost for IPv4.
- window.location.hostname.match(
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
- )
+ || window.location.hostname.match(
+ /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
+ ),
);
export function register(config) {
@@ -42,8 +42,8 @@ export function register(config) {
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
- 'This web app is being served cache-first by a service ' +
- 'worker. To learn more, visit https://bit.ly/CRA-PWA'
+ 'This web app is being served cache-first by a service '
+ + 'worker. To learn more, visit https://bit.ly/CRA-PWA',
);
});
} else {
@@ -57,7 +57,7 @@ export function register(config) {
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
- .then(registration => {
+ .then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
@@ -70,8 +70,8 @@ function registerValidSW(swUrl, config) {
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
- 'New content is available and will be used when all ' +
- 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
+ 'New content is available and will be used when all '
+ + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
);
// Execute callback
@@ -93,7 +93,7 @@ function registerValidSW(swUrl, config) {
};
};
})
- .catch(error => {
+ .catch((error) => {
console.error('Error during service worker registration:', error);
});
}
@@ -103,15 +103,15 @@ function checkValidServiceWorker(swUrl, config) {
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
- .then(response => {
+ .then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
- response.status === 404 ||
- (contentType != null && contentType.indexOf('javascript') === -1)
+ response.status === 404
+ || (contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
- navigator.serviceWorker.ready.then(registration => {
+ navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
@@ -123,7 +123,7 @@ function checkValidServiceWorker(swUrl, config) {
})
.catch(() => {
console.log(
- 'No internet connection found. App is running in offline mode.'
+ 'No internet connection found. App is running in offline mode.',
);
});
}
@@ -131,11 +131,11 @@ function checkValidServiceWorker(swUrl, config) {
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
- .then(registration => {
+ .then((registration) => {
registration.unregister();
})
- .catch(error => {
+ .catch((error) => {
console.error(error.message);
});
}
-} \ No newline at end of file
+}
diff --git a/modern/src/settings/ComputedAttributePage.js b/modern/src/settings/ComputedAttributePage.js
index 73759fa..fea613a 100644
--- a/modern/src/settings/ComputedAttributePage.js
+++ b/modern/src/settings/ComputedAttributePage.js
@@ -1,19 +1,19 @@
import React, { useState } from 'react';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControl, InputLabel, MenuItem, Select, TextField } from "@material-ui/core";
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControl, InputLabel, MenuItem, Select, TextField,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t from '../common/localization';
import EditItemView from '../EditItemView';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import positionAttributes from '../attributes/positionAttributes';
-
const useStyles = makeStyles(() => ({
details: {
flexDirection: 'column',
},
}));
-const ComputedAttributePage =() => {
-
+const ComputedAttributePage = () => {
const classes = useStyles();
const [item, setItem] = useState();
const [key, setKey] = useState();
@@ -24,20 +24,21 @@ const ComputedAttributePage =() => {
type: value.type,
}));
- const handleChange = event => {
+ const handleChange = (event) => {
const newValue = event.target.value;
setKey(newValue);
const positionAttribute = positionAttributes[newValue];
- if(positionAttribute && positionAttribute.type) {
- setItem({...item, attribute: newValue, type: positionAttribute.type});
+ if (positionAttribute && positionAttribute.type) {
+ setItem({ ...item, attribute: newValue, type: positionAttribute.type });
} else {
- setItem({...item, attribute: newValue});
+ setItem({ ...item, attribute: newValue });
}
- }
+ };
return (
<EditItemView endpoint="/attributes/computed" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="subtitle1">
@@ -48,46 +49,51 @@ const ComputedAttributePage =() => {
<TextField
margin="normal"
value={item.description || ''}
- onChange={event => setItem({...item, description: event.target.value})}
+ onChange={(event) => setItem({ ...item, description: event.target.value })}
label={t('sharedDescription')}
- variant="filled" />
+ variant="filled"
+ />
<FormControl variant="filled" margin="normal" fullWidth>
<InputLabel>{t('sharedAttribute')}</InputLabel>
- <Select
- value={item.attribute || ''}
- onChange={handleChange}>
+ <Select
+ value={item.attribute || ''}
+ onChange={handleChange}
+ >
{options.map((option) => (
<MenuItem key={option.key} value={option.key}>{option.name}</MenuItem>
))}
</Select>
- </FormControl>
+ </FormControl>
<TextField
margin="normal"
value={item.expression || ''}
- onChange={event => setItem({...item, expression: event.target.value})}
+ onChange={(event) => setItem({ ...item, expression: event.target.value })}
label={t('sharedExpression')}
multiline
rows={4}
- variant="filled" />
+ variant="filled"
+ />
<FormControl
variant="filled"
margin="normal"
fullWidth
- disabled={key in positionAttributes}>
+ disabled={key in positionAttributes}
+ >
<InputLabel>{t('sharedType')}</InputLabel>
<Select
value={item.type || ''}
- onChange={event => setItem({...item, type: event.target.value})}>
- <MenuItem value={'string'}>{t('sharedTypeString')}</MenuItem>
- <MenuItem value={'number'}>{t('sharedTypeNumber')}</MenuItem>
- <MenuItem value={'boolean'}>{t('sharedTypeBoolean')}</MenuItem>
+ onChange={(event) => setItem({ ...item, type: event.target.value })}
+ >
+ <MenuItem value="string">{t('sharedTypeString')}</MenuItem>
+ <MenuItem value="number">{t('sharedTypeNumber')}</MenuItem>
+ <MenuItem value="boolean">{t('sharedTypeBoolean')}</MenuItem>
</Select>
</FormControl>
</AccordionDetails>
</Accordion>
- }
+ )}
</EditItemView>
- )
-}
+ );
+};
export default ComputedAttributePage;
diff --git a/modern/src/settings/ComputedAttributesPage.js b/modern/src/settings/ComputedAttributesPage.js
index 1a6feab..f555259 100644
--- a/modern/src/settings/ComputedAttributesPage.js
+++ b/modern/src/settings/ComputedAttributesPage.js
@@ -1,13 +1,15 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
-import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
+import {
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
+} from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import { useSelector } from 'react-redux';
+import MainToolbar from '../MainToolbar';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
columnAction: {
width: theme.spacing(1),
padding: theme.spacing(0, 1),
@@ -18,7 +20,7 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => {
const classes = useStyles();
const [items, setItems] = useState([]);
- const adminEnabled = useSelector(state => state.session.user && state.session.user.administrator);
+ const adminEnabled = useSelector((state) => state.session.user && state.session.user.administrator);
useEffectAsync(async () => {
const response = await fetch('/api/attributes/computed');
@@ -29,45 +31,44 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => {
return (
<TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- {adminEnabled && <TableCell className={classes.columnAction} />}
- <TableCell>{t('sharedDescription')}</TableCell>
- <TableCell>{t('sharedAttribute')}</TableCell>
- <TableCell>{t('sharedExpression')}</TableCell>
- <TableCell>{t('sharedType')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {items.map((item) => (
- <TableRow key={item.id}>
- {adminEnabled &&
+ <Table>
+ <TableHead>
+ <TableRow>
+ {adminEnabled && <TableCell className={classes.columnAction} />}
+ <TableCell>{t('sharedDescription')}</TableCell>
+ <TableCell>{t('sharedAttribute')}</TableCell>
+ <TableCell>{t('sharedExpression')}</TableCell>
+ <TableCell>{t('sharedType')}</TableCell>
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ {adminEnabled
+ && (
<TableCell className={classes.columnAction} padding="none">
<IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
<MoreVertIcon />
</IconButton>
</TableCell>
- }
- <TableCell>{item.description}</TableCell>
- <TableCell>{item.attribute}</TableCell>
- <TableCell>{item.expression}</TableCell>
- <TableCell>{item.type}</TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
+ )}
+ <TableCell>{item.description}</TableCell>
+ <TableCell>{item.attribute}</TableCell>
+ <TableCell>{item.expression}</TableCell>
+ <TableCell>{item.type}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
</TableContainer>
);
-}
+};
-const ComputedAttributesPage = () => {
- return (
- <>
- <MainToolbar />
- <EditCollectionView content={ComputedAttributeView} editPath="/settings/attribute" endpoint="attributes/computed" />
- </>
- );
-}
+const ComputedAttributesPage = () => (
+ <>
+ <MainToolbar />
+ <EditCollectionView content={ComputedAttributeView} editPath="/settings/attribute" endpoint="attributes/computed" />
+ </>
+);
export default ComputedAttributesPage;
diff --git a/modern/src/settings/DriverPage.js b/modern/src/settings/DriverPage.js
index 86feab8..01400c5 100644
--- a/modern/src/settings/DriverPage.js
+++ b/modern/src/settings/DriverPage.js
@@ -1,9 +1,11 @@
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t from '../common/localization';
import EditItemView from '../EditItemView';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import EditAttributesView from '../attributes/EditAttributesView';
const useStyles = makeStyles(() => ({
@@ -19,7 +21,8 @@ const DriverPage = () => {
return (
<EditItemView endpoint="drivers" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -31,15 +34,17 @@ const DriverPage = () => {
<TextField
margin="normal"
value={item.name || ''}
- onChange={event => setItem({...item, name: event.target.value})}
+ onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled" />
+ variant="filled"
+ />
<TextField
margin="normal"
value={item.uniqueId || ''}
- onChange={event => setItem({...item, uniqueId: event.target.value})}
+ onChange={(event) => setItem({ ...item, uniqueId: event.target.value })}
label={t('deviceIdentifier')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -51,15 +56,15 @@ const DriverPage = () => {
<AccordionDetails className={classes.details}>
<EditAttributesView
attributes={item.attributes}
- setAttributes={attributes => setItem({...item, attributes})}
+ setAttributes={(attributes) => setItem({ ...item, attributes })}
definitions={{}}
- />
+ />
</AccordionDetails>
</Accordion>
</>
- }
+ )}
</EditItemView>
);
-}
+};
export default DriverPage;
diff --git a/modern/src/settings/DriversPage.js b/modern/src/settings/DriversPage.js
index 957e225..36fc12d 100644
--- a/modern/src/settings/DriversPage.js
+++ b/modern/src/settings/DriversPage.js
@@ -1,12 +1,14 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
-import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
+import {
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
+} from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
+import MainToolbar from '../MainToolbar';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
columnAction: {
width: theme.spacing(1),
padding: theme.spacing(0, 1),
@@ -27,39 +29,37 @@ const DriversView = ({ updateTimestamp, onMenuClick }) => {
return (
<TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell className={classes.columnAction} />
- <TableCell>{t('sharedName')}</TableCell>
- <TableCell>{t('deviceIdentifier')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {items.map((item) => (
- <TableRow key={item.id}>
- <TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
- <TableCell>{item.uniqueId}</TableCell>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedName')}</TableCell>
+ <TableCell>{t('deviceIdentifier')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <MoreVertIcon />
+ </IconButton>
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ <TableCell>{item.uniqueId}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
</TableContainer>
);
-}
+};
-const DriversPage = () => {
- return (
- <>
- <MainToolbar />
- <EditCollectionView content={DriversView} editPath="/settings/driver" endpoint="drivers" />
- </>
- );
-}
+const DriversPage = () => (
+ <>
+ <MainToolbar />
+ <EditCollectionView content={DriversView} editPath="/settings/driver" endpoint="drivers" />
+ </>
+);
export default DriversPage;
diff --git a/modern/src/settings/GroupPage.js b/modern/src/settings/GroupPage.js
index b9fa871..f9af0f8 100644
--- a/modern/src/settings/GroupPage.js
+++ b/modern/src/settings/GroupPage.js
@@ -1,10 +1,12 @@
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t from '../common/localization';
import EditItemView from '../EditItemView';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import EditAttributesView from '../attributes/EditAttributesView';
import deviceAttributes from '../attributes/deviceAttributes';
import SelectField from '../form/SelectField';
@@ -22,7 +24,8 @@ const GroupPage = () => {
return (
<EditItemView endpoint="groups" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -34,9 +37,10 @@ const GroupPage = () => {
<TextField
margin="normal"
value={item.name || ''}
- onChange={event => setItem({...item, name: event.target.value})}
+ onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -49,10 +53,11 @@ const GroupPage = () => {
<SelectField
margin="normal"
value={item.groupId || 0}
- onChange={event => setItem({...item, groupId: Number(event.target.value)})}
+ onChange={(event) => setItem({ ...item, groupId: Number(event.target.value) })}
endpoint="/api/groups"
label={t('groupParent')}
- variant="filled" />
+ variant="filled"
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -64,15 +69,15 @@ const GroupPage = () => {
<AccordionDetails className={classes.details}>
<EditAttributesView
attributes={item.attributes}
- setAttributes={attributes => setItem({...item, attributes})}
+ setAttributes={(attributes) => setItem({ ...item, attributes })}
definitions={deviceAttributes}
- />
+ />
</AccordionDetails>
</Accordion>
</>
- }
+ )}
</EditItemView>
);
-}
+};
export default GroupPage;
diff --git a/modern/src/settings/GroupsPage.js b/modern/src/settings/GroupsPage.js
index e274062..d592184 100644
--- a/modern/src/settings/GroupsPage.js
+++ b/modern/src/settings/GroupsPage.js
@@ -1,12 +1,14 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
-import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
+import {
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
+} from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
+import MainToolbar from '../MainToolbar';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
columnAction: {
width: theme.spacing(1),
padding: theme.spacing(0, 1),
@@ -27,37 +29,35 @@ const GroupsView = ({ updateTimestamp, onMenuClick }) => {
return (
<TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell className={classes.columnAction} />
- <TableCell>{t('sharedName')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {items.map((item) => (
- <TableRow key={item.id}>
- <TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedName')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <MoreVertIcon />
+ </IconButton>
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
</TableContainer>
);
-}
+};
-const GroupsPage = () => {
- return (
- <>
- <MainToolbar />
- <EditCollectionView content={GroupsView} editPath="/settings/group" endpoint="groups" />
- </>
- );
-}
+const GroupsPage = () => (
+ <>
+ <MainToolbar />
+ <EditCollectionView content={GroupsView} editPath="/settings/group" endpoint="groups" />
+ </>
+);
export default GroupsPage;
diff --git a/modern/src/settings/MaintenancePage.js b/modern/src/settings/MaintenancePage.js
index 3b4fde5..89ebaa1 100644
--- a/modern/src/settings/MaintenancePage.js
+++ b/modern/src/settings/MaintenancePage.js
@@ -1,14 +1,18 @@
import React, { useState } from 'react';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, TextField, FormControl, InputLabel, MenuItem, Select,
+} from '@material-ui/core';
+import InputAdornment from '@material-ui/core/InputAdornment';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t from '../common/localization';
import { prefixString } from '../common/stringUtils';
import EditItemView from '../EditItemView';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, TextField, FormControl, InputLabel, MenuItem, Select, } from '@material-ui/core';
-import InputAdornment from '@material-ui/core/InputAdornment';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import EditAttributesView from '../attributes/EditAttributesView';
import positionAttributes from '../attributes/positionAttributes';
import { useAttributePreference } from '../common/preferences';
-import { speedFromKnots, speedToKnots, distanceFromMeters, distanceToMeters } from '../common/converter';
+import {
+ speedFromKnots, speedToKnots, distanceFromMeters, distanceToMeters,
+} from '../common/converter';
const useStyles = makeStyles(() => ({
details: {
@@ -17,46 +21,46 @@ const useStyles = makeStyles(() => ({
}));
const MaintenancePage = () => {
-
const classes = useStyles();
const [item, setItem] = useState();
- const [labels, setLabels] = useState({start: '', period: ''});
+ const [labels, setLabels] = useState({ start: '', period: '' });
const speedUnit = useAttributePreference('speedUnit');
const distanceUnit = useAttributePreference('distanceUnit');
const convertToList = (attributes) => {
- let otherList = [];
- for (const key in attributes) {
+ const otherList = [];
+ Object.keys(attributes).forEach((key) => {
const value = attributes[key];
if (value.type === 'number') {
- otherList.push({key, name: value.name, type: value.type});
+ otherList.push({ key, name: value.name, type: value.type });
}
- }
+ });
return otherList;
- }
+ };
- const onMaintenanceTypeChange = event => {
+ const onMaintenanceTypeChange = (event) => {
const newValue = event.target.value;
- setItem({ ...item, type: newValue, start: 0, period: 0 });
+ setItem({
+ ...item, type: newValue, start: 0, period: 0,
+ });
const attribute = positionAttributes[newValue];
if (attribute && attribute.dataType) {
switch (attribute.dataType) {
case 'distance':
- setLabels({ ...labels, start: t(prefixString('shared', distanceUnit)), period: t(prefixString('shared', distanceUnit))});
+ setLabels({ ...labels, start: t(prefixString('shared', distanceUnit)), period: t(prefixString('shared', distanceUnit)) });
break;
case 'speed':
- setLabels({ ...labels, start: t(prefixString('shared', speedUnit)), period: t(prefixString('shared', speedUnit))});
+ setLabels({ ...labels, start: t(prefixString('shared', speedUnit)), period: t(prefixString('shared', speedUnit)) });
break;
default:
break;
}
}
- }
-
- const rawToValue = value => {
+ };
+ const rawToValue = (value) => {
const attribute = positionAttributes[item.type];
if (attribute && attribute.dataType) {
switch (attribute.dataType) {
@@ -69,10 +73,9 @@ const MaintenancePage = () => {
}
}
return value;
- }
-
- const valueToRaw = value => {
+ };
+ const valueToRaw = (value) => {
const attribute = positionAttributes[item.type];
if (attribute && attribute.dataType) {
switch (attribute.dataType) {
@@ -85,11 +88,12 @@ const MaintenancePage = () => {
}
}
return value;
- }
+ };
return (
<EditItemView endpoint="maintenance" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -101,39 +105,43 @@ const MaintenancePage = () => {
<TextField
margin="normal"
value={item.name || ''}
- onChange={event => setItem({...item, name: event.target.value})}
+ onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled" />
+ variant="filled"
+ />
<FormControl variant="filled" margin="normal" fullWidth>
<InputLabel>{t('sharedType')}</InputLabel>
- <Select
- value={item.type || ''}
- onChange={onMaintenanceTypeChange}>
- {convertToList(positionAttributes).map(({ key, name })=>(
- <MenuItem key={key} value={key}>{name}</MenuItem>
- ))}
+ <Select
+ value={item.type || ''}
+ onChange={onMaintenanceTypeChange}
+ >
+ {convertToList(positionAttributes).map(({ key, name }) => (
+ <MenuItem key={key} value={key}>{name}</MenuItem>
+ ))}
</Select>
- </FormControl>
+ </FormControl>
<TextField
margin="normal"
type="number"
value={rawToValue(item.start) || ''}
- onChange={event => setItem({...item, start: valueToRaw(event.target.value)})}
+ onChange={(event) => setItem({ ...item, start: valueToRaw(event.target.value) })}
label={t('maintenanceStart')}
variant="filled"
InputProps={{
- endAdornment: <InputAdornment position="start">{labels.start}</InputAdornment>,
- }} />
+ endAdornment: <InputAdornment position="start">{labels.start}</InputAdornment>,
+ }}
+ />
<TextField
margin="normal"
type="number"
value={rawToValue(item.period) || ''}
- onChange={event => setItem({...item, period: valueToRaw(event.target.value)})}
+ onChange={(event) => setItem({ ...item, period: valueToRaw(event.target.value) })}
label={t('maintenancePeriod')}
variant="filled"
InputProps={{
- endAdornment: <InputAdornment position="start">{labels.period}</InputAdornment>,
- }} />
+ endAdornment: <InputAdornment position="start">{labels.period}</InputAdornment>,
+ }}
+ />
</AccordionDetails>
</Accordion>
<Accordion>
@@ -145,15 +153,15 @@ const MaintenancePage = () => {
<AccordionDetails className={classes.details}>
<EditAttributesView
attributes={item.attributes}
- setAttributes={attributes => setItem({...item, attributes})}
+ setAttributes={(attributes) => setItem({ ...item, attributes })}
definitions={{}}
- />
+ />
</AccordionDetails>
- </Accordion>
+ </Accordion>
</>
- }
+ )}
</EditItemView>
);
-}
+};
export default MaintenancePage;
diff --git a/modern/src/settings/MaintenancesPage.js b/modern/src/settings/MaintenancesPage.js
index 7ba4bd2..e598bc9 100644
--- a/modern/src/settings/MaintenancesPage.js
+++ b/modern/src/settings/MaintenancesPage.js
@@ -1,7 +1,9 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
-import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
+import {
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
+} from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
+import MainToolbar from '../MainToolbar';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
@@ -10,7 +12,7 @@ import positionAttributes from '../attributes/positionAttributes';
import { formatDistance, formatSpeed } from '../common/formatter';
import { useAttributePreference } from '../common/preferences';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
columnAction: {
width: theme.spacing(1),
padding: theme.spacing(0, 1),
@@ -37,7 +39,7 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
switch (attribute.dataType) {
case 'speed':
return formatSpeed(value, speedUnit);
- case 'distance':
+ case 'distance':
return formatDistance(value, distanceUnit);
default:
return value;
@@ -45,47 +47,45 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
}
return value;
- }
+ };
return (
<TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell className={classes.columnAction} />
- <TableCell>{t('sharedName')}</TableCell>
- <TableCell>{t('sharedType')}</TableCell>
- <TableCell>{t('maintenanceStart')}</TableCell>
- <TableCell>{t('maintenancePeriod')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {items.map(item => (
- <TableRow key={item.id}>
- <TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={event => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
- <TableCell>{item.type}</TableCell>
- <TableCell>{convertAttribute(item.type, item.start)}</TableCell>
- <TableCell>{convertAttribute(item.type, item.period)}</TableCell>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedName')}</TableCell>
+ <TableCell>{t('sharedType')}</TableCell>
+ <TableCell>{t('maintenanceStart')}</TableCell>
+ <TableCell>{t('maintenancePeriod')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <MoreVertIcon />
+ </IconButton>
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ <TableCell>{item.type}</TableCell>
+ <TableCell>{convertAttribute(item.type, item.start)}</TableCell>
+ <TableCell>{convertAttribute(item.type, item.period)}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
</TableContainer>
);
-}
+};
-const MaintenacesPage = () => {
- return (
- <>
- <MainToolbar />
- <EditCollectionView content={MaintenancesView} editPath="/settings/maintenance" endpoint="maintenance" />
- </>
- );
-}
+const MaintenacesPage = () => (
+ <>
+ <MainToolbar />
+ <EditCollectionView content={MaintenancesView} editPath="/settings/maintenance" endpoint="maintenance" />
+ </>
+);
export default MaintenacesPage;
diff --git a/modern/src/settings/NotificationPage.js b/modern/src/settings/NotificationPage.js
index 33904e7..11c427f 100644
--- a/modern/src/settings/NotificationPage.js
+++ b/modern/src/settings/NotificationPage.js
@@ -1,9 +1,11 @@
import React, { useState } from 'react';
+import {
+ Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import t, { findStringKeys } from '../common/localization';
import EditItemView from '../EditItemView';
-import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox } from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { prefixString, unprefixString } from '../common/stringUtils';
import SelectField from '../form/SelectField';
@@ -18,14 +20,15 @@ const NotificationPage = () => {
const [item, setItem] = useState();
- const alarms = findStringKeys(it => it.startsWith('alarm')).map(it => ({
+ const alarms = findStringKeys((it) => it.startsWith('alarm')).map((it) => ({
key: unprefixString('alarm', it),
name: t(it),
}));
return (
<EditItemView endpoint="notifications" item={item} setItem={setItem}>
- {item &&
+ {item
+ && (
<>
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -38,47 +41,52 @@ const NotificationPage = () => {
margin="normal"
value={item.type || 'alarm'}
emptyValue={null}
- onChange={e => setItem({...item, type: e.target.value})}
+ onChange={(e) => setItem({ ...item, type: e.target.value })}
endpoint="/api/notifications/types"
- keyGetter={it => it.type}
- titleGetter={it => t(prefixString('event', it.type))}
+ keyGetter={(it) => it.type}
+ titleGetter={(it) => t(prefixString('event', it.type))}
label={t('sharedType')}
- variant="filled" />
+ variant="filled"
+ />
<SelectField
multiple
margin="normal"
value={item.notificators ? item.notificators.split(/[, ]+/) : []}
- onChange={e => setItem({...item, notificators: e.target.value.join()})}
+ onChange={(e) => setItem({ ...item, notificators: e.target.value.join() })}
endpoint="/api/notifications/notificators"
- keyGetter={it => it.type}
- titleGetter={it => t(prefixString('notificator', it.type))}
+ keyGetter={(it) => it.type}
+ titleGetter={(it) => t(prefixString('notificator', it.type))}
label={t('notificationNotificators')}
- variant="filled" />
- {(!item.type || item.type === 'alarm') &&
+ variant="filled"
+ />
+ {(!item.type || item.type === 'alarm')
+ && (
<SelectField
multiple
margin="normal"
value={item.attributes && item.attributes.alarms ? item.attributes.alarms.split(/[, ]+/) : []}
- onChange={e => setItem({...item, attributes: {...item.attributes, alarms: e.target.value.join()}})}
+ onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, alarms: e.target.value.join() } })}
data={alarms}
- keyGetter={it => it.key}
+ keyGetter={(it) => it.key}
label={t('sharedAlarms')}
- variant="filled" />
- }
+ variant="filled"
+ />
+ )}
<FormControlLabel
- control={
+ control={(
<Checkbox
checked={item.always}
- onChange={event => setItem({...item, always: event.target.checked})}
- />
- }
- label={t('notificationAlways')} />
+ onChange={(event) => setItem({ ...item, always: event.target.checked })}
+ />
+ )}
+ label={t('notificationAlways')}
+ />
</AccordionDetails>
</Accordion>
</>
- }
+ )}
</EditItemView>
);
-}
+};
export default NotificationPage;
diff --git a/modern/src/settings/NotificationsPage.js b/modern/src/settings/NotificationsPage.js
index 15da0de..4e05292 100644
--- a/modern/src/settings/NotificationsPage.js
+++ b/modern/src/settings/NotificationsPage.js
@@ -1,14 +1,16 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
-import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
+import {
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
+} from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
+import MainToolbar from '../MainToolbar';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
import { prefixString } from '../common/stringUtils';
import { formatBoolean } from '../common/formatter';
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
columnAction: {
width: theme.spacing(1),
padding: theme.spacing(0, 1),
@@ -32,7 +34,7 @@ const NotificationsView = ({ updateTimestamp, onMenuClick }) => {
return value
.split(/[, ]+/)
.filter(Boolean)
- .map(it => t(prefixString(prefix, it)))
+ .map((it) => t(prefixString(prefix, it)))
.join(', ');
}
return '';
@@ -40,43 +42,41 @@ const NotificationsView = ({ updateTimestamp, onMenuClick }) => {
return (
<TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell className={classes.columnAction} />
- <TableCell>{t('notificationType')}</TableCell>
- <TableCell>{t('notificationAlways')}</TableCell>
- <TableCell>{t('sharedAlarms')}</TableCell>
- <TableCell>{t('notificationNotificators')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {items.map(item => (
- <TableRow key={item.id}>
- <TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{t(prefixString('event', item.type))}</TableCell>
- <TableCell>{formatBoolean(item.always)}</TableCell>
- <TableCell>{formatList('alarm', item.attributes.alarms)}</TableCell>
- <TableCell>{formatList('notificator', item.notificators)}</TableCell>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('notificationType')}</TableCell>
+ <TableCell>{t('notificationAlways')}</TableCell>
+ <TableCell>{t('sharedAlarms')}</TableCell>
+ <TableCell>{t('notificationNotificators')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <MoreVertIcon />
+ </IconButton>
+ </TableCell>
+ <TableCell>{t(prefixString('event', item.type))}</TableCell>
+ <TableCell>{formatBoolean(item.always)}</TableCell>
+ <TableCell>{formatList('alarm', item.attributes.alarms)}</TableCell>
+ <TableCell>{formatList('notificator', item.notificators)}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
</TableContainer>
);
-}
+};
-const NotificationsPage = () => {
- return (
- <>
- <MainToolbar />
- <EditCollectionView content={NotificationsView} editPath="/settings/notification" endpoint="notifications" />
- </>
- );
-}
+const NotificationsPage = () => (
+ <>
+ <MainToolbar />
+ <EditCollectionView content={NotificationsView} editPath="/settings/notification" endpoint="notifications" />
+ </>
+);
export default NotificationsPage;
diff --git a/modern/src/setupProxy.js b/modern/src/setupProxy.js
index c16655c..3ab7643 100644
--- a/modern/src/setupProxy.js
+++ b/modern/src/setupProxy.js
@@ -1,6 +1,8 @@
+/* eslint-disable import/no-extraneous-dependencies */
+
const proxy = require('http-proxy-middleware');
-module.exports = function (app) {
- app.use(proxy('/api/socket', { target: 'ws://' + process.env.REACT_APP_URL_NAME, ws: true }));
- app.use(proxy('/api', { target: 'http://' + process.env.REACT_APP_URL_NAME }));
+export default (app) => {
+ app.use(proxy('/api/socket', { target: `ws://${process.env.REACT_APP_URL_NAME}`, ws: true }));
+ app.use(proxy('/api', { target: `http://${process.env.REACT_APP_URL_NAME}` }));
};
diff --git a/modern/src/store/devices.js b/modern/src/store/devices.js
index 66c1607..cca23cb 100644
--- a/modern/src/store/devices.js
+++ b/modern/src/store/devices.js
@@ -4,15 +4,15 @@ const { reducer, actions } = createSlice({
name: 'devices',
initialState: {
items: {},
- selectedId: null
+ selectedId: null,
},
reducers: {
refresh(state, action) {
state.items = {};
- action.payload.forEach(item => state.items[item['id']] = item);
+ action.payload.forEach((item) => state.items[item.id] = item);
},
update(state, action) {
- action.payload.forEach(item => state.items[item['id']] = item);
+ action.payload.forEach((item) => state.items[item.id] = item);
},
select(state, action) {
state.selectedId = action.payload.id;
@@ -20,7 +20,7 @@ const { reducer, actions } = createSlice({
remove(state, action) {
delete state.items[action.payload];
},
- }
+ },
});
export { actions as devicesActions };
diff --git a/modern/src/store/drivers.js b/modern/src/store/drivers.js
index 63522d7..38933d8 100644
--- a/modern/src/store/drivers.js
+++ b/modern/src/store/drivers.js
@@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({
},
reducers: {
update(state, action) {
- action.payload.forEach(item => state.items[item['id']] = item);
+ action.payload.forEach((item) => state.items[item.id] = item);
},
- }
+ },
});
export { actions as driversActions };
diff --git a/modern/src/store/geofences.js b/modern/src/store/geofences.js
index 504b7d0..f2b7666 100644
--- a/modern/src/store/geofences.js
+++ b/modern/src/store/geofences.js
@@ -8,12 +8,12 @@ const { reducer, actions } = createSlice({
reducers: {
refresh(state, action) {
state.items = {};
- action.payload.forEach(item => state.items[item['id']] = item);
+ action.payload.forEach((item) => state.items[item.id] = item);
},
update(state, action) {
- action.payload.forEach(item => state.items[item['id']] = item);
+ action.payload.forEach((item) => state.items[item.id] = item);
},
- }
+ },
});
export { actions as geofencesActions };
diff --git a/modern/src/store/groups.js b/modern/src/store/groups.js
index 483323f..11fc5db 100644
--- a/modern/src/store/groups.js
+++ b/modern/src/store/groups.js
@@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({
},
reducers: {
update(state, action) {
- action.payload.forEach(item => state.items[item['id']] = item);
+ action.payload.forEach((item) => state.items[item.id] = item);
},
- }
+ },
});
export { actions as groupsActions };
diff --git a/modern/src/store/maintenances.js b/modern/src/store/maintenances.js
index 0813f6b..08b2adb 100644
--- a/modern/src/store/maintenances.js
+++ b/modern/src/store/maintenances.js
@@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({
},
reducers: {
update(state, action) {
- action.payload.forEach(item => state.items[item['id']] = item);
+ action.payload.forEach((item) => state.items[item.id] = item);
},
- }
+ },
});
export { actions as maintenancesActions };
diff --git a/modern/src/store/positions.js b/modern/src/store/positions.js
index 1df468c..8858298 100644
--- a/modern/src/store/positions.js
+++ b/modern/src/store/positions.js
@@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({
},
reducers: {
update(state, action) {
- action.payload.forEach(item => state.items[item['deviceId']] = item);
+ action.payload.forEach((item) => state.items[item.deviceId] = item);
},
- }
+ },
});
export { actions as positionsActions };
diff --git a/modern/src/theme/dimensions.js b/modern/src/theme/dimensions.js
index a2403ab..fcdbaee 100644
--- a/modern/src/theme/dimensions.js
+++ b/modern/src/theme/dimensions.js
@@ -8,5 +8,5 @@ export default {
columnWidthDate: 160,
columnWidthNumber: 130,
columnWidthString: 160,
- columnWidthBoolean: 130
+ columnWidthBoolean: 130,
};
diff --git a/modern/src/theme/index.js b/modern/src/theme/index.js
index 5a3b2a9..dc0a35b 100644
--- a/modern/src/theme/index.js
+++ b/modern/src/theme/index.js
@@ -6,7 +6,7 @@ import dimensions from './dimensions';
const theme = createMuiTheme({
palette,
overrides,
- dimensions
+ dimensions,
});
export default theme;
diff --git a/modern/src/theme/overrides.js b/modern/src/theme/overrides.js
index cd6c5a5..a6d08cf 100644
--- a/modern/src/theme/overrides.js
+++ b/modern/src/theme/overrides.js
@@ -4,17 +4,17 @@ export default {
MuiFormControl: {
root: {
marginTop: 5,
- marginBottom: 5
- }
+ marginBottom: 5,
+ },
},
MuiInputLabel: {
filled: {
transform: 'translate(12px, 14px) scale(1)',
- '&$shrink' :{
- transform: 'translate(12px, -14px) scale(0.72)'
- }
+ '&$shrink': {
+ transform: 'translate(12px, -14px) scale(0.72)',
+ },
},
- },
+ },
MuiFilledInput: {
root: {
height: dimensions.inputHeight,
@@ -28,19 +28,19 @@ export default {
boxSizing: 'border-box',
'&:-webkit-autofill': {
WebkitBoxShadow: '0 0 0 100px #eeeeee inset',
- },
+ },
},
underline: {
- "&:before": {
+ '&:before': {
borderBottom: 'none',
},
- "&:after": {
+ '&:after': {
borderBottom: 'none',
},
- "&:hover:before": {
+ '&:hover:before': {
borderBottom: 'none',
- },
- }
+ },
+ },
},
MuiButton: {
root: {
@@ -48,31 +48,31 @@ export default {
marginTop: 5,
marginBottom: 5,
'&$disabled': {
- opacity: .4,
+ opacity: 0.4,
color: undefined,
- }
+ },
},
contained: {
'&$disabled': {
- opacity: .4,
+ opacity: 0.4,
color: undefined,
- backgroundColor: undefined
- }
- }
+ backgroundColor: undefined,
+ },
+ },
},
MuiFormHelperText: {
root: {
- marginBottom: -10
+ marginBottom: -10,
},
contained: {
- marginLeft: 12
- }
+ marginLeft: 12,
+ },
},
MuiAutocomplete: {
inputRoot: {
'&.MuiFilledInput-root': {
- paddingTop: 0
- }
- }
- }
+ paddingTop: 0,
+ },
+ },
+ },
};