diff options
Diffstat (limited to 'modern')
25 files changed, 381 insertions, 50 deletions
diff --git a/modern/src/common/components/PageLayout.js b/modern/src/common/components/PageLayout.js new file mode 100644 index 00000000..e37ae4dc --- /dev/null +++ b/modern/src/common/components/PageLayout.js @@ -0,0 +1,110 @@ +import React, { useState } from 'react'; +import { + AppBar, Breadcrumbs, Divider, Drawer, Hidden, IconButton, makeStyles, Toolbar, Typography, useMediaQuery, useTheme, +} from '@material-ui/core'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import MenuIcon from '@material-ui/icons/Menu'; +import { useHistory } from 'react-router-dom'; +import { useTranslation } from './LocalizationProvider'; + +const useStyles = makeStyles((theme) => ({ + desktopRoot: { + height: '100%', + display: 'flex', + }, + mobileRoot: { + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + desktopDrawer: { + width: theme.dimensions.drawerWidthDesktop, + }, + mobileDrawer: { + width: theme.dimensions.drawerWidthTablet, + }, + toolbar: theme.mixins.toolbar, + content: { + flexGrow: 1, + alignItems: 'stretch', + overflow: 'auto', + }, +})); + +const PageTitle = ({ breadcrumbs }) => { + const theme = useTheme(); + const t = useTranslation(); + + const desktop = useMediaQuery(theme.breakpoints.up('md')); + + if (desktop) { + return ( + <Typography variant="h6" noWrap>{t(breadcrumbs.at(0))}</Typography> + ); + } + return ( + <Breadcrumbs> + {breadcrumbs.slice(0, -1).map((breadcrumb) => ( + <Typography variant="h6" color="inherit" key={breadcrumb}>{t(breadcrumb)}</Typography> + ))} + <Typography variant="h6" color="textPrimary">{t(breadcrumbs.at(-1))}</Typography> + </Breadcrumbs> + ); +}; + +const PageLayout = ({ menu, breadcrumbs, children }) => { + const classes = useStyles(); + const history = useHistory(); + + const [openDrawer, setOpenDrawer] = useState(false); + + return ( + <> + <Hidden smDown> + <div className={classes.desktopRoot}> + <Drawer + variant="permanent" + className={classes.desktopDrawer} + classes={{ paper: classes.desktopDrawer }} + > + <div className={classes.toolbar}> + <Toolbar> + <IconButton color="inherit" edge="start" onClick={() => history.push('/')}> + <ArrowBackIcon /> + </IconButton> + <PageTitle breadcrumbs={breadcrumbs} /> + </Toolbar> + </div> + <Divider /> + {menu} + </Drawer> + <div className={classes.content}>{children}</div> + </div> + </Hidden> + + <Hidden mdUp> + <div className={classes.mobileRoot}> + <Drawer + variant="temporary" + open={openDrawer} + onClose={() => setOpenDrawer(false)} + classes={{ paper: classes.mobileDrawer }} + > + {menu} + </Drawer> + <AppBar position="static" color="inherit"> + <Toolbar> + <IconButton color="inherit" edge="start" onClick={() => setOpenDrawer(true)}> + <MenuIcon /> + </IconButton> + <PageTitle breadcrumbs={breadcrumbs} /> + </Toolbar> + </AppBar> + <div className={classes.content}>{children}</div> + </div> + </Hidden> + </> + ); +}; + +export default PageLayout; diff --git a/modern/src/settings/AccumulatorsPage.js b/modern/src/settings/AccumulatorsPage.js index f8895bbe..0fcde8d1 100644 --- a/modern/src/settings/AccumulatorsPage.js +++ b/modern/src/settings/AccumulatorsPage.js @@ -6,7 +6,8 @@ import { } from '@material-ui/core'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { useTranslation } from '../common/components/LocalizationProvider'; -import OptionsLayout from './components/OptionsLayout'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ container: { @@ -57,7 +58,7 @@ const AccumulatorsPage = () => { }; return ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['sharedDeviceAccumulators']}> {item && ( <Container maxWidth="xs" className={classes.container}> <Accordion defaultExpanded> @@ -107,7 +108,7 @@ const AccumulatorsPage = () => { </FormControl> </Container> )} - </OptionsLayout> + </PageLayout> ); }; diff --git a/modern/src/settings/CalendarPage.js b/modern/src/settings/CalendarPage.js index ec793196..154b3f11 100644 --- a/modern/src/settings/CalendarPage.js +++ b/modern/src/settings/CalendarPage.js @@ -8,6 +8,7 @@ import { DropzoneArea } from 'material-ui-dropzone'; import EditItemView from './components/EditItemView'; import EditAttributesView from './components/EditAttributesView'; import { useTranslation } from '../common/components/LocalizationProvider'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -37,7 +38,14 @@ const CalendarPage = () => { const validate = () => item && item.name && item.data; return ( - <EditItemView endpoint="calendars" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="calendars" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'sharedCalendar']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/CalendarsPage.js b/modern/src/settings/CalendarsPage.js index db4dc770..875530a8 100644 --- a/modern/src/settings/CalendarsPage.js +++ b/modern/src/settings/CalendarsPage.js @@ -5,8 +5,9 @@ import { import MoreVertIcon from '@material-ui/icons/MoreVert'; import { useEffectAsync } from '../reactHelper'; import EditCollectionView from './components/EditCollectionView'; -import OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -55,9 +56,9 @@ const CalendarsView = ({ updateTimestamp, onMenuClick }) => { }; const CalendarsPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedCalendars']}> <EditCollectionView content={CalendarsView} editPath="/settings/calendar" endpoint="calendars" /> - </OptionsLayout> + </PageLayout> ); export default CalendarsPage; diff --git a/modern/src/settings/CommandPage.js b/modern/src/settings/CommandPage.js index 99bb21f2..4785021b 100644 --- a/modern/src/settings/CommandPage.js +++ b/modern/src/settings/CommandPage.js @@ -6,6 +6,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditItemView from './components/EditItemView'; import { useTranslation } from '../common/components/LocalizationProvider'; import BaseCommandView from './components/BaseCommandView'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -22,7 +23,14 @@ const CommandPage = () => { const validate = () => item && item.type; return ( - <EditItemView endpoint="commands" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="commands" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'sharedSavedCommand']} + > {item && ( <Accordion defaultExpanded> <AccordionSummary expandIcon={<ExpandMoreIcon />}> diff --git a/modern/src/settings/CommandSendPage.js b/modern/src/settings/CommandSendPage.js index 79de1b84..f7e62b24 100644 --- a/modern/src/settings/CommandSendPage.js +++ b/modern/src/settings/CommandSendPage.js @@ -5,9 +5,10 @@ import { } from '@material-ui/core'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { useTranslation } from '../common/components/LocalizationProvider'; -import OptionsLayout from './components/OptionsLayout'; import BaseCommandView from './components/BaseCommandView'; import SelectField from '../common/components/SelectField'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ container: { @@ -62,7 +63,7 @@ const CommandSendPage = () => { const validate = () => savedId || (item && item.type); return ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'deviceCommand']}> <Container maxWidth="xs" className={classes.container}> <Accordion defaultExpanded> <AccordionSummary expandIcon={<ExpandMoreIcon />}> @@ -108,7 +109,7 @@ const CommandSendPage = () => { </div> </FormControl> </Container> - </OptionsLayout> + </PageLayout> ); }; diff --git a/modern/src/settings/CommandsPage.js b/modern/src/settings/CommandsPage.js index 6081b48c..20b792b8 100644 --- a/modern/src/settings/CommandsPage.js +++ b/modern/src/settings/CommandsPage.js @@ -5,10 +5,11 @@ import { import MoreVertIcon from '@material-ui/icons/MoreVert'; import { useEffectAsync } from '../reactHelper'; import EditCollectionView from './components/EditCollectionView'; -import OptionsLayout from './components/OptionsLayout'; 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'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -61,9 +62,9 @@ const CommandsView = ({ updateTimestamp, onMenuClick }) => { }; const CommandsPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedSavedCommands']}> <EditCollectionView content={CommandsView} editPath="/settings/command" endpoint="commands" /> - </OptionsLayout> + </PageLayout> ); export default CommandsPage; diff --git a/modern/src/settings/ComputedAttributePage.js b/modern/src/settings/ComputedAttributePage.js index 52a583dc..984339b8 100644 --- a/modern/src/settings/ComputedAttributePage.js +++ b/modern/src/settings/ComputedAttributePage.js @@ -6,6 +6,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditItemView from './components/EditItemView'; import { useTranslation } from '../common/components/LocalizationProvider'; import usePositionAttributes from '../common/attributes/usePositionAttributes'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -42,7 +43,14 @@ const ComputedAttributePage = () => { const validate = () => item && item.description && item.expression; return ( - <EditItemView endpoint="attributes/computed" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="attributes/computed" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'sharedComputedAttribute']} + > {item && ( <Accordion defaultExpanded> <AccordionSummary expandIcon={<ExpandMoreIcon />}> diff --git a/modern/src/settings/ComputedAttributesPage.js b/modern/src/settings/ComputedAttributesPage.js index 3b60419d..451b47a7 100644 --- a/modern/src/settings/ComputedAttributesPage.js +++ b/modern/src/settings/ComputedAttributesPage.js @@ -5,9 +5,10 @@ import { import MoreVertIcon from '@material-ui/icons/MoreVert'; import { useEffectAsync } from '../reactHelper'; import EditCollectionView from './components/EditCollectionView'; -import OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; import { useAdministrator } from '../common/util/permissions'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -65,9 +66,9 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => { }; const ComputedAttributesPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedComputedAttributes']}> <EditCollectionView content={ComputedAttributeView} editPath="/settings/attribute" endpoint="attributes/computed" /> - </OptionsLayout> + </PageLayout> ); export default ComputedAttributesPage; diff --git a/modern/src/settings/DevicePage.js b/modern/src/settings/DevicePage.js index e40649a5..491ba60f 100644 --- a/modern/src/settings/DevicePage.js +++ b/modern/src/settings/DevicePage.js @@ -14,6 +14,7 @@ import { prefixString } from '../common/util/stringUtils'; import { useTranslation } from '../common/components/LocalizationProvider'; import useDeviceAttributes from '../common/attributes/useDeviceAttributes'; import { useAdministrator } from '../common/util/permissions'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -34,7 +35,14 @@ const DevicePage = () => { const validate = () => item && item.name && item.uniqueId; return ( - <EditItemView endpoint="devices" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="devices" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['sharedDevice']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/DriverPage.js b/modern/src/settings/DriverPage.js index dee11d37..93d09c8e 100644 --- a/modern/src/settings/DriverPage.js +++ b/modern/src/settings/DriverPage.js @@ -7,6 +7,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditItemView from './components/EditItemView'; import EditAttributesView from './components/EditAttributesView'; import { useTranslation } from '../common/components/LocalizationProvider'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -23,7 +24,14 @@ const DriverPage = () => { const validate = () => item && item.name && item.uniqueId; return ( - <EditItemView endpoint="drivers" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="drivers" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'sharedDriver']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/DriversPage.js b/modern/src/settings/DriversPage.js index 5b01bdfa..f5908381 100644 --- a/modern/src/settings/DriversPage.js +++ b/modern/src/settings/DriversPage.js @@ -5,8 +5,9 @@ import { import MoreVertIcon from '@material-ui/icons/MoreVert'; import { useEffectAsync } from '../reactHelper'; import EditCollectionView from './components/EditCollectionView'; -import OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -57,9 +58,9 @@ const DriversView = ({ updateTimestamp, onMenuClick }) => { }; const DriversPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedDrivers']}> <EditCollectionView content={DriversView} editPath="/settings/driver" endpoint="drivers" /> - </OptionsLayout> + </PageLayout> ); export default DriversPage; diff --git a/modern/src/settings/GeofencePage.js b/modern/src/settings/GeofencePage.js index 0fa986d2..e23d49fb 100644 --- a/modern/src/settings/GeofencePage.js +++ b/modern/src/settings/GeofencePage.js @@ -9,6 +9,7 @@ import EditItemView from './components/EditItemView'; import EditAttributesView from './components/EditAttributesView'; import { useTranslation } from '../common/components/LocalizationProvider'; import useGeofenceAttributes from '../common/attributes/useGeofenceAttributes'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -27,7 +28,14 @@ const GeofencePage = () => { const validate = () => item && item.name; return ( - <EditItemView endpoint="geofences" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="geofences" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'sharedGeofence']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/GroupPage.js b/modern/src/settings/GroupPage.js index 750d6ebc..f56a2fd3 100644 --- a/modern/src/settings/GroupPage.js +++ b/modern/src/settings/GroupPage.js @@ -10,6 +10,7 @@ import EditAttributesView from './components/EditAttributesView'; import useDeviceAttributes from '../common/attributes/useDeviceAttributes'; import SelectField from '../common/components/SelectField'; import { useTranslation } from '../common/components/LocalizationProvider'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -28,7 +29,14 @@ const GroupPage = () => { const validate = () => item && item.name; return ( - <EditItemView endpoint="groups" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="groups" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'groupDialog']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/GroupsPage.js b/modern/src/settings/GroupsPage.js index 3642c02f..5d23c2d9 100644 --- a/modern/src/settings/GroupsPage.js +++ b/modern/src/settings/GroupsPage.js @@ -5,8 +5,9 @@ import { import MoreVertIcon from '@material-ui/icons/MoreVert'; import { useEffectAsync } from '../reactHelper'; import EditCollectionView from './components/EditCollectionView'; -import OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -55,9 +56,9 @@ const GroupsView = ({ updateTimestamp, onMenuClick }) => { }; const GroupsPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'settingsGroups']}> <EditCollectionView content={GroupsView} editPath="/settings/group" endpoint="groups" /> - </OptionsLayout> + </PageLayout> ); export default GroupsPage; diff --git a/modern/src/settings/MaintenancePage.js b/modern/src/settings/MaintenancePage.js index b55ce35b..9e53aca1 100644 --- a/modern/src/settings/MaintenancePage.js +++ b/modern/src/settings/MaintenancePage.js @@ -13,6 +13,7 @@ import { } from '../common/util/converter'; import { useTranslation } from '../common/components/LocalizationProvider'; import usePositionAttributes from '../common/attributes/usePositionAttributes'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -97,7 +98,14 @@ const MaintenancePage = () => { const validate = () => item && item.name && item.type && item.start && item.period; return ( - <EditItemView endpoint="maintenance" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="maintenance" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'sharedMaintenance']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/MaintenancesPage.js b/modern/src/settings/MaintenancesPage.js index 038e5dff..3801f010 100644 --- a/modern/src/settings/MaintenancesPage.js +++ b/modern/src/settings/MaintenancesPage.js @@ -9,8 +9,9 @@ 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 OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -85,9 +86,9 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => { }; const MaintenacesPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedMaintenance']}> <EditCollectionView content={MaintenancesView} editPath="/settings/maintenance" endpoint="maintenance" /> - </OptionsLayout> + </PageLayout> ); export default MaintenacesPage; diff --git a/modern/src/settings/NotificationPage.js b/modern/src/settings/NotificationPage.js index ed0b3e5e..38ba19e5 100644 --- a/modern/src/settings/NotificationPage.js +++ b/modern/src/settings/NotificationPage.js @@ -8,6 +8,7 @@ import { useTranslation, useTranslationKeys } from '../common/components/Localiz import EditItemView from './components/EditItemView'; import { prefixString, unprefixString } from '../common/util/stringUtils'; import SelectField from '../common/components/SelectField'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -29,7 +30,14 @@ const NotificationPage = () => { const validate = () => item && item.type && item.notificators; return ( - <EditItemView endpoint="notifications" item={item} setItem={setItem} validate={validate}> + <EditItemView + endpoint="notifications" + item={item} + setItem={setItem} + validate={validate} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'sharedNotification']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/NotificationsPage.js b/modern/src/settings/NotificationsPage.js index d96bc3da..7ad5186b 100644 --- a/modern/src/settings/NotificationsPage.js +++ b/modern/src/settings/NotificationsPage.js @@ -7,8 +7,9 @@ import { useEffectAsync } from '../reactHelper'; import EditCollectionView from './components/EditCollectionView'; import { prefixString } from '../common/util/stringUtils'; import { formatBoolean } from '../common/util/formatter'; -import OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -74,9 +75,9 @@ const NotificationsView = ({ updateTimestamp, onMenuClick }) => { }; const NotificationsPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedNotifications']}> <EditCollectionView content={NotificationsView} editPath="/settings/notification" endpoint="notifications" /> - </OptionsLayout> + </PageLayout> ); export default NotificationsPage; diff --git a/modern/src/settings/PreferencesPage.js b/modern/src/settings/PreferencesPage.js index 8b259bf2..1256a53a 100644 --- a/modern/src/settings/PreferencesPage.js +++ b/modern/src/settings/PreferencesPage.js @@ -4,8 +4,9 @@ import { } from '@material-ui/core'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { useLocalization, useTranslation } from '../common/components/LocalizationProvider'; -import OptionsLayout from './components/OptionsLayout'; import usePersistedState from '../common/util/usePersistedState'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ container: { @@ -28,7 +29,7 @@ const PreferencesPage = () => { const [mapCluster, setMapCluster] = usePersistedState('mapCluster', true); return ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedPreferences']}> <Container maxWidth="xs" className={classes.container}> <Accordion defaultExpanded> <AccordionSummary expandIcon={<ExpandMoreIcon />}> @@ -67,7 +68,7 @@ const PreferencesPage = () => { </AccordionDetails> </Accordion> </Container> - </OptionsLayout> + </PageLayout> ); }; diff --git a/modern/src/settings/ServerPage.js b/modern/src/settings/ServerPage.js index f98bc691..8943252e 100644 --- a/modern/src/settings/ServerPage.js +++ b/modern/src/settings/ServerPage.js @@ -11,9 +11,10 @@ import { sessionActions } from '../store'; import EditAttributesView from './components/EditAttributesView'; import useDeviceAttributes from '../common/attributes/useDeviceAttributes'; import useUserAttributes from '../common/attributes/useUserAttributes'; -import OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; import SelectField from '../common/components/SelectField'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ container: { @@ -57,7 +58,7 @@ const ServerPage = () => { }; return ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'settingsServer']}> <Container maxWidth="xs" className={classes.container}> {item && ( <> @@ -234,7 +235,7 @@ const ServerPage = () => { </div> </FormControl> </Container> - </OptionsLayout> + </PageLayout> ); }; diff --git a/modern/src/settings/UserPage.js b/modern/src/settings/UserPage.js index 2b5adcca..7200329a 100644 --- a/modern/src/settings/UserPage.js +++ b/modern/src/settings/UserPage.js @@ -13,6 +13,7 @@ import { useTranslation } from '../common/components/LocalizationProvider'; import useUserAttributes from '../common/attributes/useUserAttributes'; import { sessionActions } from '../store'; import SelectField from '../common/components/SelectField'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles(() => ({ details: { @@ -40,7 +41,15 @@ const UserPage = () => { const validate = () => item && item.name && item.email && (item.id || item.password); return ( - <EditItemView endpoint="users" item={item} setItem={setItem} validate={validate} onItemSaved={onItemSaved}> + <EditItemView + endpoint="users" + item={item} + setItem={setItem} + validate={validate} + onItemSaved={onItemSaved} + menu={<SettingsMenu />} + breadcrumbs={['settingsTitle', 'settingsUser']} + > {item && ( <> <Accordion defaultExpanded> diff --git a/modern/src/settings/UsersPage.js b/modern/src/settings/UsersPage.js index bdadf845..2d8d1199 100644 --- a/modern/src/settings/UsersPage.js +++ b/modern/src/settings/UsersPage.js @@ -6,8 +6,9 @@ import MoreVertIcon from '@material-ui/icons/MoreVert'; import { useEffectAsync } from '../reactHelper'; import EditCollectionView from './components/EditCollectionView'; import { formatBoolean } from '../common/util/formatter'; -import OptionsLayout from './components/OptionsLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; +import PageLayout from '../common/components/PageLayout'; +import SettingsMenu from './components/SettingsMenu'; const useStyles = makeStyles((theme) => ({ columnAction: { @@ -62,9 +63,9 @@ const UsersView = ({ updateTimestamp, onMenuClick }) => { }; const UsersPage = () => ( - <OptionsLayout> + <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'settingsUsers']}> <EditCollectionView content={UsersView} editPath="/settings/user" endpoint="users" /> - </OptionsLayout> + </PageLayout> ); export default UsersPage; diff --git a/modern/src/settings/components/EditItemView.js b/modern/src/settings/components/EditItemView.js index 90e5294a..2283ebda 100644 --- a/modern/src/settings/components/EditItemView.js +++ b/modern/src/settings/components/EditItemView.js @@ -6,8 +6,8 @@ import Button from '@material-ui/core/Button'; import FormControl from '@material-ui/core/FormControl'; import { useEffectAsync } from '../../reactHelper'; -import OptionsLayout from './OptionsLayout'; import { useTranslation } from '../../common/components/LocalizationProvider'; +import PageLayout from '../../common/components/PageLayout'; const useStyles = makeStyles((theme) => ({ container: { @@ -23,7 +23,7 @@ const useStyles = makeStyles((theme) => ({ })); const EditItemView = ({ - children, endpoint, item, setItem, validate, onItemSaved, + children, endpoint, item, setItem, validate, onItemSaved, menu, breadcrumbs, }) => { const history = useHistory(); const classes = useStyles(); @@ -63,7 +63,7 @@ const EditItemView = ({ }; return ( - <OptionsLayout> + <PageLayout menu={menu} breadcrumbs={breadcrumbs}> <Container maxWidth="xs" className={classes.container}> {children} <FormControl fullWidth margin="normal"> @@ -88,7 +88,7 @@ const EditItemView = ({ </div> </FormControl> </Container> - </OptionsLayout> + </PageLayout> ); }; diff --git a/modern/src/settings/components/SettingsMenu.js b/modern/src/settings/components/SettingsMenu.js new file mode 100644 index 00000000..036f4101 --- /dev/null +++ b/modern/src/settings/components/SettingsMenu.js @@ -0,0 +1,128 @@ +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'; +import { Link, useLocation } from 'react-router-dom'; +import { useSelector } from 'react-redux'; +import { useTranslation } from '../../common/components/LocalizationProvider'; +import { useAdministrator, useReadonly } from '../../common/util/permissions'; + +const MenuItem = ({ + title, link, icon, selected, +}) => ( + <ListItem button key={link} component={Link} to={link} selected={selected}> + <ListItemIcon>{icon}</ListItemIcon> + <ListItemText primary={title} /> + </ListItem> +); + +const SettingsMenu = () => { + const t = useTranslation(); + const location = useLocation(); + + const readonly = useReadonly(); + const admin = useAdministrator(); + const userId = useSelector((state) => state.session.user?.id); + + return ( + <> + <List> + <MenuItem + title={t('sharedPreferences')} + link="/settings/preferences" + icon={<SettingsIcon />} + selected={location.pathname === '/settings/preferences'} + /> + {!readonly && ( + <> + <MenuItem + title={t('sharedNotifications')} + link="/settings/notifications" + icon={<NotificationsIcon />} + selected={location.pathname.startsWith('/settings/notification')} + /> + <MenuItem + title={t('settingsUser')} + link={`/settings/user/${userId}`} + icon={<PersonIcon />} + selected={location.pathname === `/settings/user/${userId}`} + /> + <MenuItem + title={t('sharedGeofences')} + link="/geofences" + icon={<CreateIcon />} + selected={location.pathname.startsWith('/settings/geofence')} + /> + <MenuItem + title={t('settingsGroups')} + link="/settings/groups" + icon={<FolderIcon />} + selected={location.pathname.startsWith('/settings/group')} + /> + <MenuItem + title={t('sharedDrivers')} + link="/settings/drivers" + icon={<PersonIcon />} + selected={location.pathname.startsWith('/settings/driver')} + /> + <MenuItem + title={t('sharedCalendars')} + link="/settings/calendars" + icon={<TodayIcon />} + selected={location.pathname.startsWith('/settings/calendar')} + /> + <MenuItem + title={t('sharedComputedAttributes')} + link="/settings/attributes" + icon={<StorageIcon />} + selected={location.pathname.startsWith('/settings/attribute')} + /> + <MenuItem + title={t('sharedMaintenance')} + link="/settings/maintenances" + icon={<BuildIcon />} + selected={location.pathname.startsWith('/settings/maintenance')} + /> + <MenuItem + title={t('sharedSavedCommands')} + link="/settings/commands" + icon={<PublishIcon />} + selected={location.pathname.startsWith('/settings/command')} + /> + </> + )} + </List> + {admin && ( + <> + <Divider /> + <List> + <MenuItem + title={t('settingsServer')} + link="/settings/server" + icon={<StorageIcon />} + selected={location.pathname === '/settings/server'} + /> + <MenuItem + title={t('settingsUsers')} + link="/settings/users" + icon={<PeopleIcon />} + selected={location.pathname.startsWith('/settings/user') && location.pathname !== `/settings/user/${userId}`} + /> + </List> + </> + )} + </> + ); +}; + +export default SettingsMenu; |