aboutsummaryrefslogtreecommitdiff
path: root/modern/src/settings
diff options
context:
space:
mode:
Diffstat (limited to 'modern/src/settings')
-rw-r--r--modern/src/settings/AccumulatorsPage.js24
-rw-r--r--modern/src/settings/CalendarPage.js10
-rw-r--r--modern/src/settings/CalendarsPage.js63
-rw-r--r--modern/src/settings/CommandPage.js8
-rw-r--r--modern/src/settings/CommandSendPage.js22
-rw-r--r--modern/src/settings/CommandsPage.js71
-rw-r--r--modern/src/settings/ComputedAttributePage.js22
-rw-r--r--modern/src/settings/ComputedAttributesPage.js79
-rw-r--r--modern/src/settings/DevicePage.js27
-rw-r--r--modern/src/settings/DriverPage.js11
-rw-r--r--modern/src/settings/DriversPage.js67
-rw-r--r--modern/src/settings/GeofencePage.js10
-rw-r--r--modern/src/settings/GroupPage.js17
-rw-r--r--modern/src/settings/GroupsPage.js63
-rw-r--r--modern/src/settings/MaintenancePage.js23
-rw-r--r--modern/src/settings/MaintenancesPage.js76
-rw-r--r--modern/src/settings/NotificationPage.js111
-rw-r--r--modern/src/settings/NotificationsPage.js75
-rw-r--r--modern/src/settings/PreferencesPage.js28
-rw-r--r--modern/src/settings/ServerPage.js47
-rw-r--r--modern/src/settings/UserPage.js70
-rw-r--r--modern/src/settings/UsersPage.js75
-rw-r--r--modern/src/settings/components/AddAttributeDialog.js9
-rw-r--r--modern/src/settings/components/BaseCommandView.js4
-rw-r--r--modern/src/settings/components/CollectionActions.js48
-rw-r--r--modern/src/settings/components/CollectionFab.js36
-rw-r--r--modern/src/settings/components/EditAttributesView.js22
-rw-r--r--modern/src/settings/components/EditCollectionView.js89
-rw-r--r--modern/src/settings/components/EditItemView.js16
-rw-r--r--modern/src/settings/components/SettingsMenu.js22
30 files changed, 628 insertions, 617 deletions
diff --git a/modern/src/settings/AccumulatorsPage.js b/modern/src/settings/AccumulatorsPage.js
index b22fe02e..ce2d18a2 100644
--- a/modern/src/settings/AccumulatorsPage.js
+++ b/modern/src/settings/AccumulatorsPage.js
@@ -1,10 +1,18 @@
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
-import { useHistory, useParams } from 'react-router-dom';
+import { useNavigate, useParams } from 'react-router-dom';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Container, TextField, FormControl, Button,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ Container,
+ TextField,
+ FormControl,
+ Button,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { useTranslation } from '../common/components/LocalizationProvider';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
@@ -27,7 +35,7 @@ const useStyles = makeStyles((theme) => ({
}));
const AccumulatorsPage = () => {
- const history = useHistory();
+ const navigate = useNavigate();
const classes = useStyles();
const t = useTranslation();
@@ -54,7 +62,7 @@ const AccumulatorsPage = () => {
});
if (response.ok) {
- history.goBack();
+ navigate(-1);
} else {
throw Error(await response.text());
}
@@ -77,7 +85,6 @@ const AccumulatorsPage = () => {
value={item.hours}
onChange={(event) => setItem({ ...item, hours: Number(event.target.value) })}
label={t('positionHours')}
- variant="filled"
/>
<TextField
margin="normal"
@@ -85,7 +92,6 @@ const AccumulatorsPage = () => {
value={item.totalDistance}
onChange={(event) => setItem({ ...item, totalDistance: Number(event.target.value) })}
label={t('deviceTotalDistance')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
@@ -95,7 +101,7 @@ const AccumulatorsPage = () => {
type="button"
color="primary"
variant="outlined"
- onClick={() => history.goBack()}
+ onClick={() => navigate(-1)}
>
{t('sharedCancel')}
</Button>
diff --git a/modern/src/settings/CalendarPage.js b/modern/src/settings/CalendarPage.js
index 154b3f11..1d967a35 100644
--- a/modern/src/settings/CalendarPage.js
+++ b/modern/src/settings/CalendarPage.js
@@ -1,9 +1,10 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
+import TextField from '@mui/material/TextField';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion, AccordionSummary, AccordionDetails, Typography,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { DropzoneArea } from 'material-ui-dropzone';
import EditItemView from './components/EditItemView';
import EditAttributesView from './components/EditAttributesView';
@@ -60,7 +61,6 @@ const CalendarPage = () => {
value={item.name || ''}
onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled"
/>
<DropzoneArea
filesLimit={1}
diff --git a/modern/src/settings/CalendarsPage.js b/modern/src/settings/CalendarsPage.js
index 06697647..a3ff51d5 100644
--- a/modern/src/settings/CalendarsPage.js
+++ b/modern/src/settings/CalendarsPage.js
@@ -1,13 +1,14 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
import { useTranslation } from '../common/components/LocalizationProvider';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -16,10 +17,11 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const CalendarsView = ({ updateTimestamp, onMenuClick }) => {
+const CalendarsPage = () => {
const classes = useStyles();
const t = useTranslation();
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
useEffectAsync(async () => {
@@ -29,38 +31,33 @@ const CalendarsView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
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 size="small" onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedCalendars']}>
+ <TableContainer>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedName')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/calendar" endpoint="calendars" setTimestamp={setTimestamp} />
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ <CollectionFab editPath="/settings/calendar" />
+ </PageLayout>
);
};
-const CalendarsPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedCalendars']}>
- <EditCollectionView content={CalendarsView} editPath="/settings/calendar" endpoint="calendars" />
- </PageLayout>
-);
-
export default CalendarsPage;
diff --git a/modern/src/settings/CommandPage.js b/modern/src/settings/CommandPage.js
index 4785021b..5c306e4c 100644
--- a/modern/src/settings/CommandPage.js
+++ b/modern/src/settings/CommandPage.js
@@ -1,8 +1,9 @@
import React, { useState } from 'react';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, TextField,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion, AccordionSummary, AccordionDetails, Typography, TextField,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import EditItemView from './components/EditItemView';
import { useTranslation } from '../common/components/LocalizationProvider';
import BaseCommandView from './components/BaseCommandView';
@@ -44,7 +45,6 @@ const CommandPage = () => {
value={item.description || ''}
onChange={(event) => setItem({ ...item, description: event.target.value })}
label={t('sharedDescription')}
- variant="filled"
/>
<BaseCommandView item={item} setItem={setItem} />
</AccordionDetails>
diff --git a/modern/src/settings/CommandSendPage.js b/modern/src/settings/CommandSendPage.js
index cc0dae63..29c9df46 100644
--- a/modern/src/settings/CommandSendPage.js
+++ b/modern/src/settings/CommandSendPage.js
@@ -1,9 +1,16 @@
import React, { useState } from 'react';
-import { useHistory, useParams } from 'react-router-dom';
+import { useNavigate, useParams } from 'react-router-dom';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Container, Button, FormControl,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ Container,
+ Button,
+ FormControl,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { useTranslation } from '../common/components/LocalizationProvider';
import BaseCommandView from './components/BaseCommandView';
import SelectField from '../common/components/SelectField';
@@ -28,7 +35,7 @@ const useStyles = makeStyles((theme) => ({
}));
const CommandSendPage = () => {
- const history = useHistory();
+ const navigate = useNavigate();
const classes = useStyles();
const t = useTranslation();
@@ -59,7 +66,7 @@ const CommandSendPage = () => {
});
if (response.ok) {
- history.goBack();
+ navigate(-1);
} else {
throw Error(await response.text());
}
@@ -85,7 +92,6 @@ const CommandSendPage = () => {
endpoint={`/api/commands/send?deviceId=${deviceId}`}
titleGetter={(it) => it.description}
label={t('sharedSavedCommand')}
- variant="filled"
/>
{!savedId && (
<BaseCommandView item={item} setItem={setItem} />
@@ -98,7 +104,7 @@ const CommandSendPage = () => {
type="button"
color="primary"
variant="outlined"
- onClick={() => history.goBack()}
+ onClick={() => navigate(-1)}
>
{t('sharedCancel')}
</Button>
diff --git a/modern/src/settings/CommandsPage.js b/modern/src/settings/CommandsPage.js
index 1b09a8bd..dd1559d9 100644
--- a/modern/src/settings/CommandsPage.js
+++ b/modern/src/settings/CommandsPage.js
@@ -1,15 +1,16 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
import { useTranslation } from '../common/components/LocalizationProvider';
import { formatBoolean } from '../common/util/formatter';
import { prefixString } from '../common/util/stringUtils';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -18,10 +19,11 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const CommandsView = ({ updateTimestamp, onMenuClick }) => {
+const CommandsPage = () => {
const classes = useStyles();
const t = useTranslation();
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
useEffectAsync(async () => {
@@ -31,42 +33,37 @@ const CommandsView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
return (
- <TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell className={classes.columnAction} />
- <TableCell>{t('sharedDescription')}</TableCell>
- <TableCell>{t('sharedType')}</TableCell>
- <TableCell>{t('commandSendSms')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {items.map((item) => (
- <TableRow key={item.id}>
- <TableCell className={classes.columnAction} padding="none">
- <IconButton size="small" onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.description}</TableCell>
- <TableCell>{t(prefixString('command', item.type))}</TableCell>
- <TableCell>{formatBoolean(item.textChannel, t)}</TableCell>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedSavedCommands']}>
+ <TableContainer>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedDescription')}</TableCell>
+ <TableCell>{t('sharedType')}</TableCell>
+ <TableCell>{t('commandSendSms')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/command" endpoint="commands" setTimestamp={setTimestamp} />
+ </TableCell>
+ <TableCell>{item.description}</TableCell>
+ <TableCell>{t(prefixString('command', item.type))}</TableCell>
+ <TableCell>{formatBoolean(item.textChannel, t)}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ <CollectionFab editPath="/settings/command" />
+ </PageLayout>
);
};
-const CommandsPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedSavedCommands']}>
- <EditCollectionView content={CommandsView} editPath="/settings/command" endpoint="commands" />
- </PageLayout>
-);
-
export default CommandsPage;
diff --git a/modern/src/settings/ComputedAttributePage.js b/modern/src/settings/ComputedAttributePage.js
index 984339b8..ba5fe712 100644
--- a/modern/src/settings/ComputedAttributePage.js
+++ b/modern/src/settings/ComputedAttributePage.js
@@ -1,8 +1,17 @@
import React, { useState } from 'react';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControl, InputLabel, MenuItem, Select, TextField,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ FormControl,
+ InputLabel,
+ MenuItem,
+ Select,
+ TextField,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import EditItemView from './components/EditItemView';
import { useTranslation } from '../common/components/LocalizationProvider';
import usePositionAttributes from '../common/attributes/usePositionAttributes';
@@ -64,11 +73,11 @@ const ComputedAttributePage = () => {
value={item.description || ''}
onChange={(event) => setItem({ ...item, description: event.target.value })}
label={t('sharedDescription')}
- variant="filled"
/>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('sharedAttribute')}</InputLabel>
<Select
+ label={t('sharedAttribute')}
value={item.attribute || ''}
onChange={handleChange}
>
@@ -84,16 +93,15 @@ const ComputedAttributePage = () => {
label={t('sharedExpression')}
multiline
rows={4}
- variant="filled"
/>
<FormControl
- variant="filled"
margin="normal"
fullWidth
disabled={key in positionAttributes}
>
<InputLabel>{t('sharedType')}</InputLabel>
<Select
+ label={t('sharedType')}
value={item.type || ''}
onChange={(event) => setItem({ ...item, type: event.target.value })}
>
diff --git a/modern/src/settings/ComputedAttributesPage.js b/modern/src/settings/ComputedAttributesPage.js
index 86704c3b..b754f9fe 100644
--- a/modern/src/settings/ComputedAttributesPage.js
+++ b/modern/src/settings/ComputedAttributesPage.js
@@ -1,14 +1,15 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
import { useTranslation } from '../common/components/LocalizationProvider';
import { useAdministrator } from '../common/util/permissions';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -17,10 +18,11 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => {
+const ComputedAttributesPage = () => {
const classes = useStyles();
const t = useTranslation();
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
const administrator = useAdministrator();
@@ -31,46 +33,41 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
return (
- <TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- {administrator && <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}>
- {administrator && (
- <TableCell className={classes.columnAction} padding="none">
- <IconButton size="small" 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>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedComputedAttributes']}>
+ <TableContainer>
+ <Table>
+ <TableHead>
+ <TableRow>
+ {administrator && <TableCell className={classes.columnAction} />}
+ <TableCell>{t('sharedDescription')}</TableCell>
+ <TableCell>{t('sharedAttribute')}</TableCell>
+ <TableCell>{t('sharedExpression')}</TableCell>
+ <TableCell>{t('sharedType')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ {administrator && (
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/attribute" endpoint="attributes/computed" setTimestamp={setTimestamp} />
+ </TableCell>
+ )}
+ <TableCell>{item.description}</TableCell>
+ <TableCell>{item.attribute}</TableCell>
+ <TableCell>{item.expression}</TableCell>
+ <TableCell>{item.type}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ <CollectionFab editPath="/settings/attribute" />
+ </PageLayout>
);
};
-const ComputedAttributesPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedComputedAttributes']}>
- <EditCollectionView content={ComputedAttributeView} editPath="/settings/attribute" endpoint="attributes/computed" />
- </PageLayout>
-);
-
export default ComputedAttributesPage;
diff --git a/modern/src/settings/DevicePage.js b/modern/src/settings/DevicePage.js
index 56a589dc..3f194570 100644
--- a/modern/src/settings/DevicePage.js
+++ b/modern/src/settings/DevicePage.js
@@ -1,10 +1,16 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
+import TextField from '@mui/material/TextField';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ FormControlLabel,
+ Checkbox,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import EditItemView from './components/EditItemView';
import EditAttributesView from './components/EditAttributesView';
import SelectField from '../common/components/SelectField';
@@ -59,14 +65,12 @@ const DevicePage = () => {
value={item.name || ''}
onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.uniqueId || ''}
onChange={(event) => setItem({ ...item, uniqueId: event.target.value })}
label={t('deviceIdentifier')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
@@ -83,28 +87,24 @@ const DevicePage = () => {
onChange={(event) => setItem({ ...item, groupId: Number(event.target.value) })}
endpoint="/api/groups"
label={t('groupParent')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.phone || ''}
onChange={(event) => setItem({ ...item, phone: event.target.value })}
label={t('sharedPhone')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.model || ''}
onChange={(event) => setItem({ ...item, model: event.target.value })}
label={t('deviceModel')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.contact || ''}
onChange={(event) => setItem({ ...item, contact: event.target.value })}
label={t('deviceContact')}
- variant="filled"
/>
<SelectField
margin="normal"
@@ -116,7 +116,6 @@ const DevicePage = () => {
name: t(`category${category.replace(/^\w/, (c) => c.toUpperCase())}`),
}))}
label={t('deviceCategory')}
- variant="filled"
/>
{admin && (
<FormControlLabel
@@ -156,7 +155,6 @@ const DevicePage = () => {
keyBase="deviceId"
keyLink="geofenceId"
label={t('sharedGeofences')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -167,7 +165,6 @@ const DevicePage = () => {
keyLink="notificationId"
titleGetter={(it) => t(prefixString('event', it.type))}
label={t('sharedNotifications')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -177,7 +174,6 @@ const DevicePage = () => {
keyBase="deviceId"
keyLink="driverId"
label={t('sharedDrivers')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -188,7 +184,6 @@ const DevicePage = () => {
keyLink="attributeId"
titleGetter={(it) => it.description}
label={t('sharedComputedAttributes')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -199,7 +194,6 @@ const DevicePage = () => {
keyLink="commandId"
titleGetter={(it) => it.description}
label={t('sharedSavedCommands')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -209,7 +203,6 @@ const DevicePage = () => {
keyBase="deviceId"
keyLink="maintenanceId"
label={t('sharedMaintenance')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
diff --git a/modern/src/settings/DriverPage.js b/modern/src/settings/DriverPage.js
index 93d09c8e..707e2977 100644
--- a/modern/src/settings/DriverPage.js
+++ b/modern/src/settings/DriverPage.js
@@ -1,9 +1,10 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
+import TextField from '@mui/material/TextField';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion, AccordionSummary, AccordionDetails, Typography,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import EditItemView from './components/EditItemView';
import EditAttributesView from './components/EditAttributesView';
import { useTranslation } from '../common/components/LocalizationProvider';
@@ -46,14 +47,12 @@ const DriverPage = () => {
value={item.name || ''}
onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.uniqueId || ''}
onChange={(event) => setItem({ ...item, uniqueId: event.target.value })}
label={t('deviceIdentifier')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
diff --git a/modern/src/settings/DriversPage.js b/modern/src/settings/DriversPage.js
index 26601777..c4de30e9 100644
--- a/modern/src/settings/DriversPage.js
+++ b/modern/src/settings/DriversPage.js
@@ -1,13 +1,14 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
import { useTranslation } from '../common/components/LocalizationProvider';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -16,10 +17,11 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const DriversView = ({ updateTimestamp, onMenuClick }) => {
+const DriversPage = () => {
const classes = useStyles();
const t = useTranslation();
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
useEffectAsync(async () => {
@@ -29,40 +31,35 @@ const DriversView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
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 size="small" onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
- <TableCell>{item.uniqueId}</TableCell>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedDrivers']}>
+ <TableContainer>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedName')}</TableCell>
+ <TableCell>{t('deviceIdentifier')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/driver" endpoint="drivers" setTimestamp={setTimestamp} />
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ <TableCell>{item.uniqueId}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ <CollectionFab editPath="/settings/driver" />
+ </PageLayout>
);
};
-const DriversPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedDrivers']}>
- <EditCollectionView content={DriversView} editPath="/settings/driver" endpoint="drivers" />
- </PageLayout>
-);
-
export default DriversPage;
diff --git a/modern/src/settings/GeofencePage.js b/modern/src/settings/GeofencePage.js
index e23d49fb..353eb2b8 100644
--- a/modern/src/settings/GeofencePage.js
+++ b/modern/src/settings/GeofencePage.js
@@ -1,10 +1,11 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
+import TextField from '@mui/material/TextField';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion, AccordionSummary, AccordionDetails, Typography,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import EditItemView from './components/EditItemView';
import EditAttributesView from './components/EditAttributesView';
import { useTranslation } from '../common/components/LocalizationProvider';
@@ -50,7 +51,6 @@ const GeofencePage = () => {
value={item.name || ''}
onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
diff --git a/modern/src/settings/GroupPage.js b/modern/src/settings/GroupPage.js
index 9dcd65c9..3f4cc8d8 100644
--- a/modern/src/settings/GroupPage.js
+++ b/modern/src/settings/GroupPage.js
@@ -1,10 +1,11 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
+import TextField from '@mui/material/TextField';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion, AccordionSummary, AccordionDetails, Typography,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import EditItemView from './components/EditItemView';
import EditAttributesView from './components/EditAttributesView';
import SelectField from '../common/components/SelectField';
@@ -55,7 +56,6 @@ const GroupPage = () => {
value={item.name || ''}
onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
@@ -72,7 +72,6 @@ const GroupPage = () => {
onChange={(event) => setItem({ ...item, groupId: Number(event.target.value) })}
endpoint="/api/groups"
label={t('groupParent')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
@@ -106,7 +105,6 @@ const GroupPage = () => {
keyBase="groupId"
keyLink="geofenceId"
label={t('sharedGeofences')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -117,7 +115,6 @@ const GroupPage = () => {
keyLink="notificationId"
titleGetter={(it) => t(prefixString('event', it.type))}
label={t('sharedNotifications')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -127,7 +124,6 @@ const GroupPage = () => {
keyBase="groupId"
keyLink="driverId"
label={t('sharedDrivers')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -138,7 +134,6 @@ const GroupPage = () => {
keyLink="attributeId"
titleGetter={(it) => it.description}
label={t('sharedComputedAttributes')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -149,7 +144,6 @@ const GroupPage = () => {
keyLink="commandId"
titleGetter={(it) => it.description}
label={t('sharedSavedCommands')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -159,7 +153,6 @@ const GroupPage = () => {
keyBase="groupId"
keyLink="maintenanceId"
label={t('sharedMaintenance')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
diff --git a/modern/src/settings/GroupsPage.js b/modern/src/settings/GroupsPage.js
index 257d0bca..ebaa3b5e 100644
--- a/modern/src/settings/GroupsPage.js
+++ b/modern/src/settings/GroupsPage.js
@@ -1,13 +1,14 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
import { useTranslation } from '../common/components/LocalizationProvider';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -16,10 +17,11 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const GroupsView = ({ updateTimestamp, onMenuClick }) => {
+const GroupsPage = () => {
const classes = useStyles();
const t = useTranslation();
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
useEffectAsync(async () => {
@@ -29,38 +31,33 @@ const GroupsView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
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 size="small" onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'settingsGroups']}>
+ <TableContainer>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell className={classes.columnAction} />
+ <TableCell>{t('sharedName')}</TableCell>
</TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/group" endpoint="groups" setTimestamp={setTimestamp} />
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ <CollectionFab editPath="/settings/group" />
+ </PageLayout>
);
};
-const GroupsPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'settingsGroups']}>
- <EditCollectionView content={GroupsView} editPath="/settings/group" endpoint="groups" />
- </PageLayout>
-);
-
export default GroupsPage;
diff --git a/modern/src/settings/MaintenancePage.js b/modern/src/settings/MaintenancePage.js
index 9e53aca1..5694d77b 100644
--- a/modern/src/settings/MaintenancePage.js
+++ b/modern/src/settings/MaintenancePage.js
@@ -1,9 +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';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ TextField,
+ FormControl,
+ InputLabel,
+ MenuItem,
+ Select,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import InputAdornment from '@mui/material/InputAdornment';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { prefixString } from '../common/util/stringUtils';
import EditItemView from './components/EditItemView';
import EditAttributesView from './components/EditAttributesView';
@@ -120,11 +129,11 @@ const MaintenancePage = () => {
value={item.name || ''}
onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled"
/>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('sharedType')}</InputLabel>
<Select
+ label={t('sharedType')}
value={item.type || ''}
onChange={onMaintenanceTypeChange}
>
@@ -139,7 +148,6 @@ const MaintenancePage = () => {
value={rawToValue(item.start) || ''}
onChange={(event) => setItem({ ...item, start: valueToRaw(event.target.value) })}
label={t('maintenanceStart')}
- variant="filled"
InputProps={{
endAdornment: <InputAdornment position="start">{labels.start}</InputAdornment>,
}}
@@ -150,7 +158,6 @@ const MaintenancePage = () => {
value={rawToValue(item.period) || ''}
onChange={(event) => setItem({ ...item, period: valueToRaw(event.target.value) })}
label={t('maintenancePeriod')}
- variant="filled"
InputProps={{
endAdornment: <InputAdornment position="start">{labels.period}</InputAdornment>,
}}
diff --git a/modern/src/settings/MaintenancesPage.js b/modern/src/settings/MaintenancesPage.js
index ea00e7e1..d4a06fd2 100644
--- a/modern/src/settings/MaintenancesPage.js
+++ b/modern/src/settings/MaintenancesPage.js
@@ -1,17 +1,17 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
-
import usePositionAttributes from '../common/attributes/usePositionAttributes';
import { formatDistance, formatSpeed } from '../common/util/formatter';
import { useAttributePreference } from '../common/util/preferences';
import { useTranslation } from '../common/components/LocalizationProvider';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -20,12 +20,13 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
+const MaintenacesPage = () => {
const classes = useStyles();
const t = useTranslation();
const positionAttributes = usePositionAttributes(t);
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
const speedUnit = useAttributePreference('speedUnit');
const distanceUnit = useAttributePreference('distanceUnit');
@@ -37,7 +38,7 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
const convertAttribute = (key, value) => {
const attribute = positionAttributes[key];
@@ -56,41 +57,36 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
};
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 size="small" 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>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedMaintenance']}>
+ <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>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/maintenance" endpoint="maintenance" setTimestamp={setTimestamp} />
+ </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>
+ <CollectionFab editPath="/settings/maintenance" />
+ </PageLayout>
);
};
-const MaintenacesPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedMaintenance']}>
- <EditCollectionView content={MaintenancesView} editPath="/settings/maintenance" endpoint="maintenance" />
- </PageLayout>
-);
-
export default MaintenacesPage;
diff --git a/modern/src/settings/NotificationPage.js b/modern/src/settings/NotificationPage.js
index 38ba19e5..a7c06f68 100644
--- a/modern/src/settings/NotificationPage.js
+++ b/modern/src/settings/NotificationPage.js
@@ -1,9 +1,15 @@
import React, { useState } from 'react';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ FormControlLabel,
+ Checkbox,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { useTranslation, useTranslationKeys } from '../common/components/LocalizationProvider';
import EditItemView from './components/EditItemView';
import { prefixString, unprefixString } from '../common/util/stringUtils';
@@ -39,60 +45,55 @@ const NotificationPage = () => {
breadcrumbs={['settingsTitle', 'sharedNotification']}
>
{item && (
- <>
- <Accordion defaultExpanded>
- <AccordionSummary expandIcon={<ExpandMoreIcon />}>
- <Typography variant="subtitle1">
- {t('sharedRequired')}
- </Typography>
- </AccordionSummary>
- <AccordionDetails className={classes.details}>
- <SelectField
- margin="normal"
- value={item.type}
- emptyValue={null}
- onChange={(e) => setItem({ ...item, type: e.target.value })}
- endpoint="/api/notifications/types"
- keyGetter={(it) => it.type}
- titleGetter={(it) => t(prefixString('event', it.type))}
- label={t('sharedType')}
- variant="filled"
- />
- <SelectField
- multiple
- margin="normal"
- value={item.notificators ? item.notificators.split(/[, ]+/) : []}
- onChange={(e) => setItem({ ...item, notificators: e.target.value.join() })}
- endpoint="/api/notifications/notificators"
- keyGetter={(it) => it.type}
- titleGetter={(it) => t(prefixString('notificator', it.type))}
- label={t('notificationNotificators')}
- 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() } })}
- data={alarms}
- keyGetter={(it) => it.key}
- label={t('sharedAlarms')}
- variant="filled"
+ <Accordion defaultExpanded>
+ <AccordionSummary expandIcon={<ExpandMoreIcon />}>
+ <Typography variant="subtitle1">
+ {t('sharedRequired')}
+ </Typography>
+ </AccordionSummary>
+ <AccordionDetails className={classes.details}>
+ <SelectField
+ margin="normal"
+ value={item.type}
+ emptyValue={null}
+ onChange={(e) => setItem({ ...item, type: e.target.value })}
+ endpoint="/api/notifications/types"
+ keyGetter={(it) => it.type}
+ titleGetter={(it) => t(prefixString('event', it.type))}
+ label={t('sharedType')}
+ />
+ <SelectField
+ multiple
+ margin="normal"
+ value={item.notificators ? item.notificators.split(/[, ]+/) : []}
+ onChange={(e) => setItem({ ...item, notificators: e.target.value.join() })}
+ endpoint="/api/notifications/notificators"
+ keyGetter={(it) => it.type}
+ titleGetter={(it) => t(prefixString('notificator', it.type))}
+ label={t('notificationNotificators')}
+ />
+ {(!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() } })}
+ data={alarms}
+ keyGetter={(it) => it.key}
+ label={t('sharedAlarms')}
+ />
+ )}
+ <FormControlLabel
+ control={(
+ <Checkbox
+ checked={item.always}
+ onChange={(event) => setItem({ ...item, always: event.target.checked })}
/>
- )}
- <FormControlLabel
- control={(
- <Checkbox
- checked={item.always}
- onChange={(event) => setItem({ ...item, always: event.target.checked })}
- />
)}
- label={t('notificationAlways')}
- />
- </AccordionDetails>
- </Accordion>
- </>
+ label={t('notificationAlways')}
+ />
+ </AccordionDetails>
+ </Accordion>
)}
</EditItemView>
);
diff --git a/modern/src/settings/NotificationsPage.js b/modern/src/settings/NotificationsPage.js
index de3e762f..ae463dd3 100644
--- a/modern/src/settings/NotificationsPage.js
+++ b/modern/src/settings/NotificationsPage.js
@@ -1,15 +1,16 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
import { prefixString } from '../common/util/stringUtils';
import { formatBoolean } from '../common/util/formatter';
import { useTranslation } from '../common/components/LocalizationProvider';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -18,10 +19,11 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const NotificationsView = ({ updateTimestamp, onMenuClick }) => {
+const NotificationsPage = () => {
const classes = useStyles();
const t = useTranslation();
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
useEffectAsync(async () => {
@@ -31,7 +33,7 @@ const NotificationsView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
const formatList = (prefix, value) => {
if (value) {
@@ -45,41 +47,36 @@ 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 size="small" onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{t(prefixString('event', item.type))}</TableCell>
- <TableCell>{formatBoolean(item.always, t)}</TableCell>
- <TableCell>{formatList('alarm', item.attributes.alarms)}</TableCell>
- <TableCell>{formatList('notificator', item.notificators)}</TableCell>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedNotifications']}>
+ <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>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/notification" endpoint="notifications" setTimestamp={setTimestamp} />
+ </TableCell>
+ <TableCell>{t(prefixString('event', item.type))}</TableCell>
+ <TableCell>{formatBoolean(item.always, t)}</TableCell>
+ <TableCell>{formatList('alarm', item.attributes.alarms)}</TableCell>
+ <TableCell>{formatList('notificator', item.notificators)}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ <CollectionFab editPath="/settings/notification" />
+ </PageLayout>
);
};
-const NotificationsPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedNotifications']}>
- <EditCollectionView content={NotificationsView} editPath="/settings/notification" endpoint="notifications" />
- </PageLayout>
-);
-
export default NotificationsPage;
diff --git a/modern/src/settings/PreferencesPage.js b/modern/src/settings/PreferencesPage.js
index 94d55adf..93ded1f0 100644
--- a/modern/src/settings/PreferencesPage.js
+++ b/modern/src/settings/PreferencesPage.js
@@ -1,8 +1,19 @@
import React from 'react';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Container, FormControl, InputLabel, Select, MenuItem, Checkbox, FormControlLabel,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ Container,
+ FormControl,
+ InputLabel,
+ Select,
+ MenuItem,
+ Checkbox,
+ FormControlLabel,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { useLocalization, useTranslation } from '../common/components/LocalizationProvider';
import usePersistedState from '../common/util/usePersistedState';
import PageLayout from '../common/components/PageLayout';
@@ -42,9 +53,13 @@ const PreferencesPage = () => {
</Typography>
</AccordionSummary>
<AccordionDetails className={classes.details}>
- <FormControl variant="filled" fullWidth>
+ <FormControl fullWidth>
<InputLabel>{t('loginLanguage')}</InputLabel>
- <Select value={language} onChange={(e) => setLanguage(e.target.value)}>
+ <Select
+ label={t('loginLanguage')}
+ value={language}
+ onChange={(e) => setLanguage(e.target.value)}
+ >
{languageList.map((it) => <MenuItem key={it.code} value={it.code}>{it.name}</MenuItem>)}
</Select>
</FormControl>
@@ -57,9 +72,10 @@ const PreferencesPage = () => {
</Typography>
</AccordionSummary>
<AccordionDetails className={classes.details}>
- <FormControl variant="filled" fullWidth>
+ <FormControl fullWidth>
<InputLabel>{t('sharedAttributes')}</InputLabel>
<Select
+ label={t('sharedAttributes')}
value={positionItems}
onChange={(e) => setPositionItems(e.target.value)}
renderValue={(it) => it.length}
diff --git a/modern/src/settings/ServerPage.js b/modern/src/settings/ServerPage.js
index b745cb96..80353deb 100644
--- a/modern/src/settings/ServerPage.js
+++ b/modern/src/settings/ServerPage.js
@@ -1,11 +1,23 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
+import TextField from '@mui/material/TextField';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Button, FormControl, Container, Checkbox, FormControlLabel, InputLabel, Select, MenuItem,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
-import { useHistory } from 'react-router-dom';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ Button,
+ FormControl,
+ Container,
+ Checkbox,
+ FormControlLabel,
+ InputLabel,
+ Select,
+ MenuItem,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import { useNavigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { sessionActions } from '../store';
import EditAttributesView from './components/EditAttributesView';
@@ -35,7 +47,7 @@ const useStyles = makeStyles((theme) => ({
const ServerPage = () => {
const classes = useStyles();
- const history = useHistory();
+ const navigate = useNavigate();
const dispatch = useDispatch();
const t = useTranslation();
@@ -54,7 +66,7 @@ const ServerPage = () => {
if (response.ok) {
dispatch(sessionActions.updateServer(await response.json()));
- history.goBack();
+ navigate(-1);
} else {
throw Error(await response.text());
}
@@ -77,7 +89,6 @@ const ServerPage = () => {
value={item.mapUrl || ''}
onChange={(event) => setItem({ ...item, mapUrl: event.target.value })}
label={t('mapCustomLabel')}
- variant="filled"
/>
<TextField
margin="normal"
@@ -85,7 +96,6 @@ const ServerPage = () => {
value={item.latitude || 0}
onChange={(event) => setItem({ ...item, latitude: Number(event.target.value) })}
label={t('positionLatitude')}
- variant="filled"
/>
<TextField
margin="normal"
@@ -93,7 +103,6 @@ const ServerPage = () => {
value={item.longitude || 0}
onChange={(event) => setItem({ ...item, longitude: Number(event.target.value) })}
label={t('positionLongitude')}
- variant="filled"
/>
<TextField
margin="normal"
@@ -101,11 +110,11 @@ const ServerPage = () => {
value={item.zoom || 0}
onChange={(event) => setItem({ ...item, zoom: Number(event.target.value) })}
label={t('serverZoom')}
- variant="filled"
/>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsCoordinateFormat')}</InputLabel>
<Select
+ label={t('settingsCoordinateFormat')}
value={item.coordinateFormat || 'dd'}
onChange={(event) => setItem({ ...item, coordinateFormat: event.target.value })}
>
@@ -114,9 +123,10 @@ const ServerPage = () => {
<MenuItem value="dms">{t('sharedDegreesMinutesSeconds')}</MenuItem>
</Select>
</FormControl>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsSpeedUnit')}</InputLabel>
<Select
+ label={t('settingsSpeedUnit')}
value={item.attributes.speedUnit || 'kn'}
onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, speedUnit: e.target.value } })}
>
@@ -125,9 +135,10 @@ const ServerPage = () => {
<MenuItem value="mph">{t('sharedMph')}</MenuItem>
</Select>
</FormControl>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsDistanceUnit')}</InputLabel>
<Select
+ label={t('settingsDistanceUnit')}
value={item.attributes.distanceUnit || 'km'}
onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, distanceUnit: e.target.value } })}
>
@@ -136,9 +147,10 @@ const ServerPage = () => {
<MenuItem value="nmi">{t('sharedNmi')}</MenuItem>
</Select>
</FormControl>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsVolumeUnit')}</InputLabel>
<Select
+ label={t('settingsVolumeUnit')}
value={item.attributes.volumeUnit || 'ltr'}
onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, volumeUnit: e.target.value } })}
>
@@ -156,21 +168,18 @@ const ServerPage = () => {
keyGetter={(it) => it}
titleGetter={(it) => it}
label={t('sharedTimezone')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.poiLayer || ''}
onChange={(event) => setItem({ ...item, poiLayer: event.target.value })}
label={t('mapPoiLayer')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.announcement || ''}
onChange={(event) => setItem({ ...item, announcement: event.target.value })}
label={t('serverAnnouncement')}
- variant="filled"
/>
<FormControlLabel
control={<Checkbox checked={item.twelveHourFormat} onChange={(event) => setItem({ ...item, twelveHourFormat: event.target.checked })} />}
@@ -229,7 +238,7 @@ const ServerPage = () => {
)}
<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={() => navigate(-1)}>
{t('sharedCancel')}
</Button>
<Button type="button" color="primary" variant="contained" onClick={handleSave}>
diff --git a/modern/src/settings/UserPage.js b/modern/src/settings/UserPage.js
index a0f6f753..d9238c22 100644
--- a/modern/src/settings/UserPage.js
+++ b/modern/src/settings/UserPage.js
@@ -1,11 +1,24 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
+import TextField from '@mui/material/TextField';
import {
- Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControl, InputLabel, Select, MenuItem, FormControlLabel, Checkbox, InputAdornment, IconButton, FilledInput,
-} from '@material-ui/core';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
-import CachedIcon from '@material-ui/icons/Cached';
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Typography,
+ FormControl,
+ InputLabel,
+ Select,
+ MenuItem,
+ FormControlLabel,
+ Checkbox,
+ InputAdornment,
+ IconButton,
+ OutlinedInput,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import CachedIcon from '@mui/icons-material/Cached';
import { useDispatch, useSelector } from 'react-redux';
import moment from 'moment';
import EditItemView from './components/EditItemView';
@@ -74,21 +87,18 @@ const UserPage = () => {
value={item.name || ''}
onChange={(event) => setItem({ ...item, name: event.target.value })}
label={t('sharedName')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.email || ''}
onChange={(event) => setItem({ ...item, email: event.target.value })}
label={t('userEmail')}
- variant="filled"
/>
<TextField
margin="normal"
type="password"
onChange={(event) => setItem({ ...item, password: event.target.value })}
label={t('userPassword')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
@@ -104,7 +114,6 @@ const UserPage = () => {
value={item.phone || ''}
onChange={(event) => setItem({ ...item, phone: event.target.value })}
label={t('sharedPhone')}
- variant="filled"
/>
<TextField
margin="normal"
@@ -112,7 +121,6 @@ const UserPage = () => {
value={item.latitude || 0}
onChange={(event) => setItem({ ...item, latitude: Number(event.target.value) })}
label={t('positionLatitude')}
- variant="filled"
/>
<TextField
margin="normal"
@@ -120,7 +128,6 @@ const UserPage = () => {
value={item.longitude || 0}
onChange={(event) => setItem({ ...item, longitude: Number(event.target.value) })}
label={t('positionLongitude')}
- variant="filled"
/>
<TextField
margin="normal"
@@ -128,11 +135,11 @@ const UserPage = () => {
value={item.zoom || 0}
onChange={(event) => setItem({ ...item, zoom: Number(event.target.value) })}
label={t('serverZoom')}
- variant="filled"
/>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsCoordinateFormat')}</InputLabel>
<Select
+ label={t('settingsCoordinateFormat')}
value={item.coordinateFormat || 'dd'}
onChange={(event) => setItem({ ...item, coordinateFormat: event.target.value })}
>
@@ -141,9 +148,10 @@ const UserPage = () => {
<MenuItem value="dms">{t('sharedDegreesMinutesSeconds')}</MenuItem>
</Select>
</FormControl>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsSpeedUnit')}</InputLabel>
<Select
+ label={t('settingsSpeedUnit')}
value={(item.attributes && item.attributes.speedUnit) || 'kn'}
onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, speedUnit: e.target.value } })}
>
@@ -152,9 +160,10 @@ const UserPage = () => {
<MenuItem value="mph">{t('sharedMph')}</MenuItem>
</Select>
</FormControl>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsDistanceUnit')}</InputLabel>
<Select
+ label={t('settingsDistanceUnit')}
value={(item.attributes && item.attributes.distanceUnit) || 'km'}
onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, distanceUnit: e.target.value } })}
>
@@ -163,9 +172,10 @@ const UserPage = () => {
<MenuItem value="nmi">{t('sharedNmi')}</MenuItem>
</Select>
</FormControl>
- <FormControl variant="filled" margin="normal" fullWidth>
+ <FormControl margin="normal" fullWidth>
<InputLabel>{t('settingsVolumeUnit')}</InputLabel>
<Select
+ label={t('settingsVolumeUnit')}
value={(item.attributes && item.attributes.volumeUnit) || 'ltr'}
onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, volumeUnit: e.target.value } })}
>
@@ -183,14 +193,12 @@ const UserPage = () => {
keyGetter={(it) => it}
titleGetter={(it) => it}
label={t('sharedTimezone')}
- variant="filled"
/>
<TextField
margin="normal"
value={item.poiLayer || ''}
onChange={(event) => setItem({ ...item, poiLayer: event.target.value })}
label={t('mapPoiLayer')}
- variant="filled"
/>
<FormControlLabel
control={<Checkbox checked={item.twelveHourFormat} onChange={(event) => setItem({ ...item, twelveHourFormat: event.target.checked })} />}
@@ -205,18 +213,19 @@ const UserPage = () => {
</Typography>
</AccordionSummary>
<AccordionDetails className={classes.details}>
- <FormControl variant="filled" margin="normal">
+ <FormControl margin="normal">
<InputLabel>{t('userToken')}</InputLabel>
- <FilledInput
+ <OutlinedInput
type="text"
value={item.token || ''}
onChange={(e) => setItem({ ...item, token: e.target.value })}
endAdornment={(
<InputAdornment position="end">
- <IconButton onClick={() => {
- const token = [...Array(30)].map(() => Math.random().toString(36)[2]).join('');
- setItem({ ...item, token });
- }}
+ <IconButton
+ onClick={() => {
+ const token = [...Array(30)].map(() => Math.random().toString(36)[2]).join('');
+ setItem({ ...item, token });
+ }}
>
<CachedIcon />
</IconButton>
@@ -226,7 +235,6 @@ const UserPage = () => {
</FormControl>
<TextField
margin="normal"
- variant="filled"
label={t('userExpirationTime')}
type="date"
value={(item.expirationTime && item.expirationTime.format(moment.HTML5_FMT.DATE)) || '2999-01-01'}
@@ -239,7 +247,6 @@ const UserPage = () => {
value={item.deviceLimit || 0}
onChange={(e) => setItem({ ...item, deviceLimit: Number(e.target.value) })}
label={t('userDeviceLimit')}
- variant="filled"
disabled={!admin}
/>
<TextField
@@ -248,7 +255,6 @@ const UserPage = () => {
value={item.userLimit || 0}
onChange={(e) => setItem({ ...item, userLimit: Number(e.target.value) })}
label={t('userUserLimit')}
- variant="filled"
disabled={!admin}
/>
<FormControlLabel
@@ -313,7 +319,6 @@ const UserPage = () => {
keyBase="userId"
keyLink="deviceId"
label={t('deviceTitle')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -323,7 +328,6 @@ const UserPage = () => {
keyBase="userId"
keyLink="groupId"
label={t('settingsGroups')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -333,7 +337,6 @@ const UserPage = () => {
keyBase="userId"
keyLink="geofenceId"
label={t('sharedGeofences')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -344,7 +347,6 @@ const UserPage = () => {
keyLink="notificationId"
titleGetter={(it) => t(prefixString('event', it.type))}
label={t('sharedNotifications')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -354,7 +356,6 @@ const UserPage = () => {
keyBase="userId"
keyLink="calendarId"
label={t('sharedCalendars')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -364,7 +365,6 @@ const UserPage = () => {
keyBase="userId"
keyLink="managedUserId"
label={t('settingsUsers')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -375,7 +375,6 @@ const UserPage = () => {
keyLink="attributeId"
titleGetter={(it) => it.description}
label={t('sharedComputedAttributes')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -385,7 +384,6 @@ const UserPage = () => {
keyBase="userId"
keyLink="driverId"
label={t('sharedDrivers')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -396,7 +394,6 @@ const UserPage = () => {
keyLink="commandId"
titleGetter={(it) => it.description}
label={t('sharedSavedCommands')}
- variant="filled"
/>
<LinkField
margin="normal"
@@ -406,7 +403,6 @@ const UserPage = () => {
keyBase="userId"
keyLink="maintenanceId"
label={t('sharedMaintenance')}
- variant="filled"
/>
</AccordionDetails>
</Accordion>
diff --git a/modern/src/settings/UsersPage.js b/modern/src/settings/UsersPage.js
index 235ae4c7..8f3aca46 100644
--- a/modern/src/settings/UsersPage.js
+++ b/modern/src/settings/UsersPage.js
@@ -1,14 +1,15 @@
import React, { useState } from 'react';
import {
- TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton,
-} from '@material-ui/core';
-import MoreVertIcon from '@material-ui/icons/MoreVert';
+ TableContainer, Table, TableRow, TableCell, TableHead, TableBody,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
import { useEffectAsync } from '../reactHelper';
-import EditCollectionView from './components/EditCollectionView';
import { formatBoolean } from '../common/util/formatter';
import { useTranslation } from '../common/components/LocalizationProvider';
import PageLayout from '../common/components/PageLayout';
import SettingsMenu from './components/SettingsMenu';
+import CollectionFab from './components/CollectionFab';
+import CollectionActions from './components/CollectionActions';
const useStyles = makeStyles((theme) => ({
columnAction: {
@@ -17,10 +18,11 @@ const useStyles = makeStyles((theme) => ({
},
}));
-const UsersView = ({ updateTimestamp, onMenuClick }) => {
+const UsersPage = () => {
const classes = useStyles();
const t = useTranslation();
+ const [timestamp, setTimestamp] = useState(Date.now());
const [items, setItems] = useState([]);
useEffectAsync(async () => {
@@ -30,44 +32,39 @@ const UsersView = ({ updateTimestamp, onMenuClick }) => {
} else {
throw Error(await response.text());
}
- }, [updateTimestamp]);
+ }, [timestamp]);
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 size="small" onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
- <MoreVertIcon />
- </IconButton>
- </TableCell>
- <TableCell>{item.name}</TableCell>
- <TableCell>{item.email}</TableCell>
- <TableCell>{formatBoolean(item.administrator, t)}</TableCell>
- <TableCell>{formatBoolean(item.disabled, t)}</TableCell>
+ <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'settingsUsers']}>
+ <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>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className={classes.columnAction} padding="none">
+ <CollectionActions itemId={item.id} editPath="/settings/user" endpoint="users" setTimestamp={setTimestamp} />
+ </TableCell>
+ <TableCell>{item.name}</TableCell>
+ <TableCell>{item.email}</TableCell>
+ <TableCell>{formatBoolean(item.administrator, t)}</TableCell>
+ <TableCell>{formatBoolean(item.disabled, t)}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ <CollectionFab editPath="/settings/user" />
+ </PageLayout>
);
};
-const UsersPage = () => (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'settingsUsers']}>
- <EditCollectionView content={UsersView} editPath="/settings/user" endpoint="users" />
- </PageLayout>
-);
-
export default UsersPage;
diff --git a/modern/src/settings/components/AddAttributeDialog.js b/modern/src/settings/components/AddAttributeDialog.js
index e7965360..de5d22b7 100644
--- a/modern/src/settings/components/AddAttributeDialog.js
+++ b/modern/src/settings/components/AddAttributeDialog.js
@@ -1,9 +1,10 @@
import React, { useState } from 'react';
import {
Button, Dialog, DialogActions, DialogContent, FormControl, InputLabel, MenuItem, Select, TextField,
-} from '@material-ui/core';
+ Autocomplete,
+} from '@mui/material';
-import { Autocomplete, createFilterOptions } from '@material-ui/lab';
+import { createFilterOptions } from '@mui/material/useAutocomplete';
import { useTranslation } from '../../common/components/LocalizationProvider';
const AddAttributeDialog = ({ open, onResult, definitions }) => {
@@ -47,17 +48,17 @@ const AddAttributeDialog = ({ open, onResult, definitions }) => {
renderOption={(option) => option.name}
freeSolo
renderInput={(params) => (
- <TextField {...params} label={t('sharedAttribute')} variant="filled" margin="normal" />
+ <TextField {...params} label={t('sharedAttribute')} margin="normal" />
)}
/>
<FormControl
- variant="filled"
margin="normal"
fullWidth
disabled={key in definitions}
>
<InputLabel>{t('sharedType')}</InputLabel>
<Select
+ label={t('sharedType')}
value={type}
onChange={(e) => setType(e.target.value)}
>
diff --git a/modern/src/settings/components/BaseCommandView.js b/modern/src/settings/components/BaseCommandView.js
index 836e8789..c578e111 100644
--- a/modern/src/settings/components/BaseCommandView.js
+++ b/modern/src/settings/components/BaseCommandView.js
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import {
TextField, FormControlLabel, Checkbox,
-} from '@material-ui/core';
+} from '@mui/material';
import { useTranslation } from '../../common/components/LocalizationProvider';
import SelectField from '../../common/components/SelectField';
import { prefixString } from '../../common/util/stringUtils';
@@ -32,7 +32,6 @@ const BaseCommandView = ({ item, setItem }) => {
keyGetter={(it) => it.type}
titleGetter={(it) => t(prefixString('command', it.type))}
label={t('sharedType')}
- variant="filled"
/>
{attributes.map(({ key, name, type }) => {
if (type === 'boolean') {
@@ -63,7 +62,6 @@ const BaseCommandView = ({ item, setItem }) => {
setItem(updateItem);
}}
label={name}
- variant="filled"
/>
);
})}
diff --git a/modern/src/settings/components/CollectionActions.js b/modern/src/settings/components/CollectionActions.js
new file mode 100644
index 00000000..c5e14949
--- /dev/null
+++ b/modern/src/settings/components/CollectionActions.js
@@ -0,0 +1,48 @@
+import React, { useState } from 'react';
+import { IconButton, Menu, MenuItem } from '@mui/material';
+import MoreVertIcon from '@mui/icons-material/MoreVert';
+import { useNavigate } from 'react-router-dom';
+import RemoveDialog from '../../common/components/RemoveDialog';
+import { useTranslation } from '../../common/components/LocalizationProvider';
+
+const CollectionActions = ({
+ itemId, editPath, endpoint, setTimestamp,
+}) => {
+ const navigate = useNavigate();
+ const t = useTranslation();
+
+ const [menuAnchorEl, setMenuAnchorEl] = useState(null);
+ const [removing, setRemoving] = useState(false);
+
+ const handleEdit = () => {
+ navigate(`${editPath}/${itemId}`);
+ setMenuAnchorEl(null);
+ };
+
+ const handleRemove = () => {
+ setRemoving(true);
+ setMenuAnchorEl(null);
+ };
+
+ const handleRemoveResult = (removed) => {
+ setRemoving(false);
+ if (removed) {
+ setTimestamp(Date.now());
+ }
+ };
+
+ return (
+ <>
+ <IconButton size="small" onClick={(event) => setMenuAnchorEl(event.currentTarget)}>
+ <MoreVertIcon />
+ </IconButton>
+ <Menu open={!!menuAnchorEl} anchorEl={menuAnchorEl} onClose={() => setMenuAnchorEl(null)}>
+ <MenuItem onClick={handleEdit}>{t('sharedEdit')}</MenuItem>
+ <MenuItem onClick={handleRemove}>{t('sharedRemove')}</MenuItem>
+ </Menu>
+ <RemoveDialog style={{ transform: 'none' }} open={removing} endpoint={endpoint} itemId={itemId} onResult={handleRemoveResult} />
+ </>
+ );
+};
+
+export default CollectionActions;
diff --git a/modern/src/settings/components/CollectionFab.js b/modern/src/settings/components/CollectionFab.js
new file mode 100644
index 00000000..2fb5b5c9
--- /dev/null
+++ b/modern/src/settings/components/CollectionFab.js
@@ -0,0 +1,36 @@
+import React from 'react';
+import { Fab } from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import AddIcon from '@mui/icons-material/Add';
+import { useNavigate } from 'react-router-dom';
+import { useReadonly } from '../../common/util/permissions';
+import dimensions from '../../common/theme/dimensions';
+
+const useStyles = makeStyles((theme) => ({
+ fab: {
+ position: 'fixed',
+ bottom: theme.spacing(2),
+ right: theme.spacing(2),
+ [theme.breakpoints.down('md')]: {
+ bottom: dimensions.bottomBarHeight + theme.spacing(2),
+ },
+ },
+}));
+
+const CollectionFab = ({ editPath, disabled }) => {
+ const classes = useStyles();
+ const navigate = useNavigate();
+
+ const readonly = useReadonly();
+
+ if (!readonly && !disabled) {
+ return (
+ <Fab size="medium" color="primary" className={classes.fab} onClick={() => navigate(editPath)}>
+ <AddIcon />
+ </Fab>
+ );
+ }
+ return '';
+};
+
+export default CollectionFab;
diff --git a/modern/src/settings/components/EditAttributesView.js b/modern/src/settings/components/EditAttributesView.js
index e28909e9..e6e1ddf0 100644
--- a/modern/src/settings/components/EditAttributesView.js
+++ b/modern/src/settings/components/EditAttributesView.js
@@ -1,10 +1,19 @@
import React, { useState } from 'react';
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';
+ Button,
+ Checkbox,
+ OutlinedInput,
+ FormControl,
+ FormControlLabel,
+ Grid,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import CloseIcon from '@mui/icons-material/Close';
+import AddIcon from '@mui/icons-material/Add';
import AddAttributeDialog from './AddAttributeDialog';
import { useTranslation } from '../../common/components/LocalizationProvider';
import { useAttributePreference } from '../../common/util/preferences';
@@ -164,9 +173,9 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => {
);
}
return (
- <FormControl variant="filled" margin="normal" key={key}>
+ <FormControl margin="normal" key={key}>
<InputLabel>{getAttributeName(key, subtype)}</InputLabel>
- <FilledInput
+ <OutlinedInput
type={type === 'number' ? 'number' : 'text'}
value={getDisplayValue(value, subtype)}
onChange={(e) => updateAttribute(key, e.target.value, type, subtype)}
@@ -182,7 +191,6 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => {
);
})}
<Button
- size="large"
variant="outlined"
color="primary"
onClick={() => setAddDialogShown(true)}
diff --git a/modern/src/settings/components/EditCollectionView.js b/modern/src/settings/components/EditCollectionView.js
deleted file mode 100644
index b0bf3ea0..00000000
--- a/modern/src/settings/components/EditCollectionView.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import React, { useState } from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import { useHistory } from 'react-router-dom';
-import Menu from '@material-ui/core/Menu';
-import MenuItem from '@material-ui/core/MenuItem';
-import Fab from '@material-ui/core/Fab';
-import AddIcon from '@material-ui/icons/Add';
-
-import RemoveDialog from '../../common/components/RemoveDialog';
-import { useTranslation } from '../../common/components/LocalizationProvider';
-import dimensions from '../../common/theme/dimensions';
-import { useReadonly } from '../../common/util/permissions';
-
-const useStyles = makeStyles((theme) => ({
- fab: {
- position: 'fixed',
- bottom: theme.spacing(2),
- right: theme.spacing(2),
- [theme.breakpoints.down('sm')]: {
- bottom: dimensions.bottomBarHeight + theme.spacing(2),
- },
- },
-}));
-
-const EditCollectionView = ({
- content, editPath, endpoint, disableAdd, filter,
-}) => {
- const classes = useStyles();
- const history = useHistory();
- const t = useTranslation();
-
- const readonly = useReadonly();
-
- const [selectedId, setSelectedId] = useState(null);
- const [selectedAnchorEl, setSelectedAnchorEl] = useState(null);
- const [removeDialogShown, setRemoveDialogShown] = useState(false);
- const [updateTimestamp, setUpdateTimestamp] = useState(Date.now());
-
- 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 = (removed) => {
- setRemoveDialogShown(false);
- if (removed) {
- setUpdateTimestamp(Date.now());
- }
- };
-
- const Content = content;
-
- return (
- <>
- <Content updateTimestamp={updateTimestamp} onMenuClick={menuShow} filter={filter} />
- {!readonly && !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>
- </Menu>
- <RemoveDialog open={removeDialogShown} endpoint={endpoint} itemId={selectedId} onResult={handleRemoveResult} />
- </>
- );
-};
-
-export default EditCollectionView;
diff --git a/modern/src/settings/components/EditItemView.js b/modern/src/settings/components/EditItemView.js
index 28598e77..83624b8f 100644
--- a/modern/src/settings/components/EditItemView.js
+++ b/modern/src/settings/components/EditItemView.js
@@ -1,9 +1,9 @@
import React from 'react';
-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 { useNavigate, useParams } from 'react-router-dom';
+import makeStyles from '@mui/styles/makeStyles';
+import Container from '@mui/material/Container';
+import Button from '@mui/material/Button';
+import FormControl from '@mui/material/FormControl';
import { useCatch, useEffectAsync } from '../../reactHelper';
import { useTranslation } from '../../common/components/LocalizationProvider';
@@ -25,7 +25,7 @@ const useStyles = makeStyles((theme) => ({
const EditItemView = ({
children, endpoint, item, setItem, defaultItem, validate, onItemSaved, menu, breadcrumbs,
}) => {
- const history = useHistory();
+ const navigate = useNavigate();
const classes = useStyles();
const t = useTranslation();
@@ -60,7 +60,7 @@ const EditItemView = ({
if (onItemSaved) {
onItemSaved(await response.json());
}
- history.goBack();
+ navigate(-1);
} else {
throw Error(await response.text());
}
@@ -76,7 +76,7 @@ const EditItemView = ({
type="button"
color="primary"
variant="outlined"
- onClick={() => history.goBack()}
+ onClick={() => navigate(-1)}
>
{t('sharedCancel')}
</Button>
diff --git a/modern/src/settings/components/SettingsMenu.js b/modern/src/settings/components/SettingsMenu.js
index 036f4101..cb2dba2f 100644
--- a/modern/src/settings/components/SettingsMenu.js
+++ b/modern/src/settings/components/SettingsMenu.js
@@ -1,17 +1,17 @@
import React from 'react';
import {
Divider, List, ListItem, ListItemIcon, ListItemText,
-} from '@material-ui/core';
-import SettingsIcon from '@material-ui/icons/Settings';
-import CreateIcon from '@material-ui/icons/Create';
-import NotificationsIcon from '@material-ui/icons/Notifications';
-import FolderIcon from '@material-ui/icons/Folder';
-import PersonIcon from '@material-ui/icons/Person';
-import StorageIcon from '@material-ui/icons/Storage';
-import BuildIcon from '@material-ui/icons/Build';
-import PeopleIcon from '@material-ui/icons/People';
-import TodayIcon from '@material-ui/icons/Today';
-import PublishIcon from '@material-ui/icons/Publish';
+} from '@mui/material';
+import SettingsIcon from '@mui/icons-material/Settings';
+import CreateIcon from '@mui/icons-material/Create';
+import NotificationsIcon from '@mui/icons-material/Notifications';
+import FolderIcon from '@mui/icons-material/Folder';
+import PersonIcon from '@mui/icons-material/Person';
+import StorageIcon from '@mui/icons-material/Storage';
+import BuildIcon from '@mui/icons-material/Build';
+import PeopleIcon from '@mui/icons-material/People';
+import TodayIcon from '@mui/icons-material/Today';
+import PublishIcon from '@mui/icons-material/Publish';
import { Link, useLocation } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { useTranslation } from '../../common/components/LocalizationProvider';