From 85a3576f3046f5bcf3bbac6ad952ef180762fd51 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 15 Jul 2022 18:45:44 -0700 Subject: Option to hide attributes --- .../common/attributes/useCommonUserAttributes.js | 4 + modern/src/common/util/useFeatures.js | 2 + modern/src/settings/CalendarPage.js | 21 +- modern/src/settings/DevicePage.js | 21 +- modern/src/settings/DriverPage.js | 21 +- modern/src/settings/GeofencePage.js | 21 +- modern/src/settings/GroupPage.js | 21 +- modern/src/settings/MaintenancePage.js | 21 +- modern/src/settings/ServerPage.js | 21 +- modern/src/settings/UserPage.js | 23 +-- .../settings/components/EditAttributesAccordion.js | 229 +++++++++++++++++++++ .../src/settings/components/EditAttributesView.js | 208 ------------------- web/l10n/en.json | 1 + 13 files changed, 285 insertions(+), 329 deletions(-) create mode 100644 modern/src/settings/components/EditAttributesAccordion.js delete mode 100644 modern/src/settings/components/EditAttributesView.js diff --git a/modern/src/common/attributes/useCommonUserAttributes.js b/modern/src/common/attributes/useCommonUserAttributes.js index 81ceaca7..791f46d4 100644 --- a/modern/src/common/attributes/useCommonUserAttributes.js +++ b/modern/src/common/attributes/useCommonUserAttributes.js @@ -37,6 +37,10 @@ export default (t) => useMemo(() => ({ name: t('attributeUiDisableGroups'), type: 'boolean', }, + 'ui.disableAttributes': { + name: t('attributeUiDisableAttributes'), + type: 'boolean', + }, 'ui.disableEvents': { name: t('attributeUiDisableEvents'), type: 'boolean', diff --git a/modern/src/common/util/useFeatures.js b/modern/src/common/util/useFeatures.js index 995fbf86..58c1bbf1 100644 --- a/modern/src/common/util/useFeatures.js +++ b/modern/src/common/util/useFeatures.js @@ -16,6 +16,7 @@ const get = (server, user, key) => { export default () => useSelector((state) => { const { server, user } = state.session; + const disableAttributes = get(server, user, 'ui.disableAttributes'); const disableVehicleFetures = get(server, user, 'ui.disableVehicleFetures'); const disableDrivers = disableVehicleFetures || get(server, user, 'ui.disableDrivers'); const disableMaintenance = disableVehicleFetures || get(server, user, 'ui.disableMaintenance'); @@ -25,6 +26,7 @@ export default () => useSelector((state) => { const disableCalendars = get(server, user, 'ui.disableCalendars'); return { + disableAttributes, disableDrivers, disableMaintenance, disableGroups, diff --git a/modern/src/settings/CalendarPage.js b/modern/src/settings/CalendarPage.js index 463b7d8c..896a77c4 100644 --- a/modern/src/settings/CalendarPage.js +++ b/modern/src/settings/CalendarPage.js @@ -7,7 +7,7 @@ import makeStyles from '@mui/styles/makeStyles'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { DropzoneArea } from 'react-mui-dropzone'; import EditItemView from './components/EditItemView'; -import EditAttributesView from './components/EditAttributesView'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import { useTranslation } from '../common/components/LocalizationProvider'; import SettingsMenu from './components/SettingsMenu'; import components from '../common/theme/components'; @@ -72,20 +72,11 @@ const CalendarPage = () => { /> - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={{}} - /> - - + setItem({ ...item, attributes })} + definitions={{}} + /> )} diff --git a/modern/src/settings/DevicePage.js b/modern/src/settings/DevicePage.js index cecd2066..d0d5dd5e 100644 --- a/modern/src/settings/DevicePage.js +++ b/modern/src/settings/DevicePage.js @@ -13,7 +13,7 @@ import makeStyles from '@mui/styles/makeStyles'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { DropzoneArea } from 'react-mui-dropzone'; import EditItemView from './components/EditItemView'; -import EditAttributesView from './components/EditAttributesView'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import SelectField from '../common/components/SelectField'; import deviceCategories from '../common/util/deviceCategories'; import LinkField from '../common/components/LinkField'; @@ -158,20 +158,11 @@ const DevicePage = () => { )} - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={{ ...commonDeviceAttributes, ...deviceAttributes }} - /> - - + setItem({ ...item, attributes })} + definitions={{ ...commonDeviceAttributes, ...deviceAttributes }} + /> {item.id && ( }> diff --git a/modern/src/settings/DriverPage.js b/modern/src/settings/DriverPage.js index 30f5106f..83d1f88f 100644 --- a/modern/src/settings/DriverPage.js +++ b/modern/src/settings/DriverPage.js @@ -6,7 +6,7 @@ import { import makeStyles from '@mui/styles/makeStyles'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import EditItemView from './components/EditItemView'; -import EditAttributesView from './components/EditAttributesView'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import { useTranslation } from '../common/components/LocalizationProvider'; import SettingsMenu from './components/SettingsMenu'; @@ -57,20 +57,11 @@ const DriverPage = () => { /> - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={{}} - /> - - + setItem({ ...item, attributes })} + definitions={{}} + /> )} diff --git a/modern/src/settings/GeofencePage.js b/modern/src/settings/GeofencePage.js index d7d1c50c..3bebea30 100644 --- a/modern/src/settings/GeofencePage.js +++ b/modern/src/settings/GeofencePage.js @@ -7,7 +7,7 @@ import { import makeStyles from '@mui/styles/makeStyles'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import EditItemView from './components/EditItemView'; -import EditAttributesView from './components/EditAttributesView'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import { useTranslation } from '../common/components/LocalizationProvider'; import useGeofenceAttributes from '../common/attributes/useGeofenceAttributes'; import SettingsMenu from './components/SettingsMenu'; @@ -77,20 +77,11 @@ const GeofencePage = () => { /> - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={geofenceAttributes} - /> - - + setItem({ ...item, attributes })} + definitions={geofenceAttributes} + /> )} diff --git a/modern/src/settings/GroupPage.js b/modern/src/settings/GroupPage.js index c4c0fa5c..b4b0a92a 100644 --- a/modern/src/settings/GroupPage.js +++ b/modern/src/settings/GroupPage.js @@ -7,7 +7,7 @@ import { import makeStyles from '@mui/styles/makeStyles'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import EditItemView from './components/EditItemView'; -import EditAttributesView from './components/EditAttributesView'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import SelectField from '../common/components/SelectField'; import LinkField from '../common/components/LinkField'; import { useTranslation } from '../common/components/LocalizationProvider'; @@ -79,20 +79,11 @@ const GroupPage = () => { /> - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={{ ...commonDeviceAttributes, ...groupAttributes }} - /> - - + setItem({ ...item, attributes })} + definitions={{ ...commonDeviceAttributes, ...groupAttributes }} + /> {item.id && ( }> diff --git a/modern/src/settings/MaintenancePage.js b/modern/src/settings/MaintenancePage.js index d2cf02d9..c434f11e 100644 --- a/modern/src/settings/MaintenancePage.js +++ b/modern/src/settings/MaintenancePage.js @@ -15,7 +15,7 @@ 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'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import { useAttributePreference } from '../common/util/preferences'; import { speedFromKnots, speedToKnots, distanceFromMeters, distanceToMeters, @@ -164,20 +164,11 @@ const MaintenancePage = () => { /> - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={{}} - /> - - + setItem({ ...item, attributes })} + definitions={{}} + /> )} diff --git a/modern/src/settings/ServerPage.js b/modern/src/settings/ServerPage.js index ee2d5f31..22dd66af 100644 --- a/modern/src/settings/ServerPage.js +++ b/modern/src/settings/ServerPage.js @@ -21,7 +21,7 @@ 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'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import { useTranslation } from '../common/components/LocalizationProvider'; import SelectField from '../common/components/SelectField'; import PageLayout from '../common/components/PageLayout'; @@ -241,20 +241,11 @@ const ServerPage = () => { - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={{ ...commonUserAttributes, ...commonDeviceAttributes, ...serverAttributes }} - /> - - + setItem({ ...item, attributes })} + definitions={{ ...commonUserAttributes, ...commonDeviceAttributes, ...serverAttributes }} + /> )}
diff --git a/modern/src/settings/UserPage.js b/modern/src/settings/UserPage.js index 6ca55187..5d29c0b4 100644 --- a/modern/src/settings/UserPage.js +++ b/modern/src/settings/UserPage.js @@ -23,7 +23,7 @@ import CachedIcon from '@mui/icons-material/Cached'; import { useDispatch, useSelector } from 'react-redux'; import moment from 'moment'; import EditItemView from './components/EditItemView'; -import EditAttributesView from './components/EditAttributesView'; +import EditAttributesAccordion from './components/EditAttributesAccordion'; import LinkField from '../common/components/LinkField'; import { useTranslation } from '../common/components/LocalizationProvider'; import useUserAttributes from '../common/attributes/useUserAttributes'; @@ -314,21 +314,12 @@ const UserPage = () => { - - }> - - {t('sharedAttributes')} - - - - setItem({ ...item, attributes })} - definitions={{ ...commonUserAttributes, ...userAttributes }} - focusAttribute={attribute} - /> - - + setItem({ ...item, attributes })} + definitions={{ ...commonUserAttributes, ...userAttributes }} + focusAttribute={attribute} + /> {item.id && manager && ( }> diff --git a/modern/src/settings/components/EditAttributesAccordion.js b/modern/src/settings/components/EditAttributesAccordion.js new file mode 100644 index 00000000..d159dafe --- /dev/null +++ b/modern/src/settings/components/EditAttributesAccordion.js @@ -0,0 +1,229 @@ +import React, { useState } from 'react'; + +import { + Button, + Checkbox, + OutlinedInput, + FormControl, + FormControlLabel, + Grid, + IconButton, + InputAdornment, + InputLabel, + Accordion, + AccordionSummary, + Typography, + AccordionDetails, +} from '@mui/material'; +import makeStyles from '@mui/styles/makeStyles'; +import CloseIcon from '@mui/icons-material/Close'; +import AddIcon from '@mui/icons-material/Add'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import AddAttributeDialog from './AddAttributeDialog'; +import { useTranslation } from '../../common/components/LocalizationProvider'; +import { useAttributePreference } from '../../common/util/preferences'; +import { + distanceFromMeters, distanceToMeters, distanceUnitString, speedFromKnots, speedToKnots, speedUnitString, volumeFromLiters, volumeToLiters, volumeUnitString, +} from '../../common/util/converter'; +import useFeatures from '../../common/util/useFeatures'; + +const useStyles = makeStyles((theme) => ({ + removeButton: { + marginRight: theme.spacing(1.5), + }, + details: { + display: 'flex', + flexDirection: 'column', + gap: theme.spacing(2), + paddingBottom: theme.spacing(3), + }, +})); + +const EditAttributesAccordion = ({ attributes, setAttributes, definitions, focusAttribute }) => { + const classes = useStyles(); + const t = useTranslation(); + + const features = useFeatures(); + + const speedUnit = useAttributePreference('speedUnit'); + const distanceUnit = useAttributePreference('distanceUnit'); + const volumeUnit = useAttributePreference('volumeUnit'); + + const [addDialogShown, setAddDialogShown] = useState(false); + + const updateAttribute = (key, value, type, subtype) => { + const updatedAttributes = { ...attributes }; + switch (subtype) { + case 'speed': + updatedAttributes[key] = speedToKnots(Number(value), speedUnit); + break; + case 'distance': + updatedAttributes[key] = distanceToMeters(Number(value), distanceUnit); + break; + case 'volume': + updatedAttributes[key] = volumeToLiters(Number(value), volumeUnit); + break; + default: + updatedAttributes[key] = type === 'number' ? Number(value) : value; + break; + } + setAttributes(updatedAttributes); + }; + + const deleteAttribute = (key) => { + const updatedAttributes = { ...attributes }; + delete updatedAttributes[key]; + setAttributes(updatedAttributes); + }; + + const getAttributeName = (key, subtype) => { + const definition = definitions[key]; + const name = definition ? definition.name : key; + switch (subtype) { + case 'speed': + return `${name} (${speedUnitString(speedUnit, t)})`; + case 'distance': + return `${name} (${distanceUnitString(distanceUnit, t)})`; + case 'volume': + return `${name} (${volumeUnitString(volumeUnit, t)})`; + default: + return name; + } + }; + + const getAttributeType = (value) => { + if (typeof value === 'number') { + return 'number'; + } if (typeof value === 'boolean') { + return 'boolean'; + } + return 'string'; + }; + + const getAttributeSubtype = (key) => { + const definition = definitions[key]; + return definition && definition.subtype; + }; + + const getDisplayValue = (value, subtype) => { + if (value) { + switch (subtype) { + case 'speed': + return speedFromKnots(value, speedUnit); + case 'distance': + return distanceFromMeters(value, distanceUnit); + case 'volume': + return volumeFromLiters(value, volumeUnit); + default: + return value; + } + } + return ''; + }; + + const convertToList = (attributes) => { + const booleanList = []; + const otherList = []; + const excludeAttributes = ['speedUnit', 'distanceUnit', 'volumeUnit', 'timezone']; + Object.keys(attributes || []).filter((key) => !excludeAttributes.includes(key)).forEach((key) => { + const value = attributes[key]; + const type = getAttributeType(value); + const subtype = getAttributeSubtype(key); + if (type === 'boolean') { + booleanList.push({ + key, value, type, subtype, + }); + } else { + otherList.push({ + key, value, type, subtype, + }); + } + }); + return [...otherList, ...booleanList]; + }; + + const handleAddResult = (definition) => { + setAddDialogShown(false); + if (definition) { + switch (definition.type) { + case 'number': + updateAttribute(definition.key, 0); + break; + case 'boolean': + updateAttribute(definition.key, false); + break; + default: + updateAttribute(definition.key, ''); + break; + } + } + }; + + return features.disableAttributes ? '' : ( + + }> + + {t('sharedAttributes')} + + + + {convertToList(attributes).map(({ + key, value, type, subtype, + }) => { + if (type === 'boolean') { + return ( + + updateAttribute(key, e.target.checked)} + /> + )} + label={getAttributeName(key, subtype)} + /> + deleteAttribute(key)}> + + + + ); + } + return ( + + {getAttributeName(key, subtype)} + updateAttribute(key, e.target.value, type, subtype)} + autoFocus={focusAttribute === key} + endAdornment={( + + deleteAttribute(key)}> + + + + )} + /> + + ); + })} + + + + + ); +}; + +export default EditAttributesAccordion; diff --git a/modern/src/settings/components/EditAttributesView.js b/modern/src/settings/components/EditAttributesView.js deleted file mode 100644 index 3329d7bc..00000000 --- a/modern/src/settings/components/EditAttributesView.js +++ /dev/null @@ -1,208 +0,0 @@ -import React, { useState } from 'react'; - -import { - 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'; -import { - distanceFromMeters, distanceToMeters, distanceUnitString, speedFromKnots, speedToKnots, speedUnitString, volumeFromLiters, volumeToLiters, volumeUnitString, -} from '../../common/util/converter'; - -const useStyles = makeStyles((theme) => ({ - removeButton: { - marginRight: theme.spacing(1.5), - }, -})); - -const EditAttributesView = ({ attributes, setAttributes, definitions, focusAttribute }) => { - const classes = useStyles(); - const t = useTranslation(); - - const speedUnit = useAttributePreference('speedUnit'); - const distanceUnit = useAttributePreference('distanceUnit'); - const volumeUnit = useAttributePreference('volumeUnit'); - - const [addDialogShown, setAddDialogShown] = useState(false); - - const updateAttribute = (key, value, type, subtype) => { - const updatedAttributes = { ...attributes }; - switch (subtype) { - case 'speed': - updatedAttributes[key] = speedToKnots(Number(value), speedUnit); - break; - case 'distance': - updatedAttributes[key] = distanceToMeters(Number(value), distanceUnit); - break; - case 'volume': - updatedAttributes[key] = volumeToLiters(Number(value), volumeUnit); - break; - default: - updatedAttributes[key] = type === 'number' ? Number(value) : value; - break; - } - setAttributes(updatedAttributes); - }; - - const deleteAttribute = (key) => { - const updatedAttributes = { ...attributes }; - delete updatedAttributes[key]; - setAttributes(updatedAttributes); - }; - - const getAttributeName = (key, subtype) => { - const definition = definitions[key]; - const name = definition ? definition.name : key; - switch (subtype) { - case 'speed': - return `${name} (${speedUnitString(speedUnit, t)})`; - case 'distance': - return `${name} (${distanceUnitString(distanceUnit, t)})`; - case 'volume': - return `${name} (${volumeUnitString(volumeUnit, t)})`; - default: - return name; - } - }; - - const getAttributeType = (value) => { - if (typeof value === 'number') { - return 'number'; - } if (typeof value === 'boolean') { - return 'boolean'; - } - return 'string'; - }; - - const getAttributeSubtype = (key) => { - const definition = definitions[key]; - return definition && definition.subtype; - }; - - const getDisplayValue = (value, subtype) => { - if (value) { - switch (subtype) { - case 'speed': - return speedFromKnots(value, speedUnit); - case 'distance': - return distanceFromMeters(value, distanceUnit); - case 'volume': - return volumeFromLiters(value, volumeUnit); - default: - return value; - } - } - return ''; - }; - - const convertToList = (attributes) => { - const booleanList = []; - const otherList = []; - const excludeAttributes = ['speedUnit', 'distanceUnit', 'volumeUnit', 'timezone']; - Object.keys(attributes || []).filter((key) => !excludeAttributes.includes(key)).forEach((key) => { - const value = attributes[key]; - const type = getAttributeType(value); - const subtype = getAttributeSubtype(key); - if (type === 'boolean') { - booleanList.push({ - key, value, type, subtype, - }); - } else { - otherList.push({ - key, value, type, subtype, - }); - } - }); - return [...otherList, ...booleanList]; - }; - - const handleAddResult = (definition) => { - setAddDialogShown(false); - if (definition) { - switch (definition.type) { - case 'number': - updateAttribute(definition.key, 0); - break; - case 'boolean': - updateAttribute(definition.key, false); - break; - default: - updateAttribute(definition.key, ''); - break; - } - } - }; - - return ( - <> - {convertToList(attributes).map(({ - key, value, type, subtype, - }) => { - if (type === 'boolean') { - return ( - - updateAttribute(key, e.target.checked)} - /> - )} - label={getAttributeName(key, subtype)} - /> - deleteAttribute(key)}> - - - - ); - } - return ( - - {getAttributeName(key, subtype)} - updateAttribute(key, e.target.value, type, subtype)} - autoFocus={focusAttribute === key} - endAdornment={( - - deleteAttribute(key)}> - - - - )} - /> - - ); - })} - - - - ); -}; - -export default EditAttributesView; diff --git a/web/l10n/en.json b/web/l10n/en.json index d846c479..16d02655 100644 --- a/web/l10n/en.json +++ b/web/l10n/en.json @@ -117,6 +117,7 @@ "attributeMailSmtpAuth": "Mail: SMTP Auth Enable", "attributeMailSmtpUsername": "Mail: SMTP Username", "attributeMailSmtpPassword": "Mail: SMTP Password", + "attributeUiDisableAttributes": "UI: Disable Attributes", "attributeUiDisableGroups": "UI: Disable Groups", "attributeUiDisableEvents": "UI: Disable Events", "attributeUiDisableVehicleFetures": "UI: Disable Vehicle Fetures", -- cgit v1.2.3