From f2bd440c7fdf8857a5704f214d96aba3345a14e7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 20 Apr 2022 18:11:16 -0700 Subject: Add saved commands --- modern/src/App.js | 4 ++ modern/src/attributes/EditAttributesView.js | 2 +- modern/src/attributes/useCommandAttributes.js | 11 ++++ modern/src/settings/CommandPage.js | 85 +++++++++++++++++++++++++++ modern/src/settings/CommandsPage.js | 69 ++++++++++++++++++++++ modern/src/settings/ComputedAttributePage.js | 2 +- modern/src/settings/OptionsLayout.js | 4 +- 7 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 modern/src/attributes/useCommandAttributes.js create mode 100644 modern/src/settings/CommandPage.js create mode 100644 modern/src/settings/CommandsPage.js diff --git a/modern/src/App.js b/modern/src/App.js index 9417feab..1d7b2cae 100644 --- a/modern/src/App.js +++ b/modern/src/App.js @@ -30,6 +30,8 @@ import ComputedAttributesPage from './settings/ComputedAttributesPage'; import ComputedAttributePage from './settings/ComputedAttributePage'; import MaintenancesPage from './settings/MaintenancesPage'; import MaintenancePage from './settings/MaintenancePage'; +import CommandsPage from './settings/CommandsPage'; +import CommandPage from './settings/CommandPage'; import StatisticsPage from './admin/StatisticsPage'; import CachingController from './CachingController'; @@ -111,6 +113,8 @@ const App = () => { + + diff --git a/modern/src/attributes/EditAttributesView.js b/modern/src/attributes/EditAttributesView.js index e8ab83e1..3a18a9a3 100644 --- a/modern/src/attributes/EditAttributesView.js +++ b/modern/src/attributes/EditAttributesView.js @@ -116,7 +116,7 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => { - )} + )} /> ); diff --git a/modern/src/attributes/useCommandAttributes.js b/modern/src/attributes/useCommandAttributes.js new file mode 100644 index 00000000..1212d283 --- /dev/null +++ b/modern/src/attributes/useCommandAttributes.js @@ -0,0 +1,11 @@ +import { useMemo } from 'react'; + +export default (t) => useMemo(() => ({ + custom: [ + { + key: 'data', + name: t('commandData'), + type: 'string', + }, + ], +}), [t]); diff --git a/modern/src/settings/CommandPage.js b/modern/src/settings/CommandPage.js new file mode 100644 index 00000000..8a7f5b94 --- /dev/null +++ b/modern/src/settings/CommandPage.js @@ -0,0 +1,85 @@ +import React, { useEffect, useState } from 'react'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, TextField, FormControlLabel, Checkbox, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import EditItemView from '../EditItemView'; +import { useTranslation } from '../LocalizationProvider'; +import SelectField from '../form/SelectField'; +import { prefixString } from '../common/stringUtils'; +import useCommandAttributes from '../attributes/useCommandAttributes'; + +const useStyles = makeStyles(() => ({ + details: { + flexDirection: 'column', + }, +})); + +const CommandPage = () => { + const classes = useStyles(); + const t = useTranslation(); + + const availableAttributes = useCommandAttributes(t); + + const [item, setItem] = useState(); + const [attributes, setAttributes] = useState([]); + + useEffect(() => { + if (item && item.type) { + setAttributes(availableAttributes[item.type] || []); + } + }, [availableAttributes, item]); + + return ( + + {item && ( + + }> + + {t('sharedRequired')} + + + + setItem({ ...item, description: event.target.value })} + label={t('sharedDescription')} + variant="filled" + /> + setItem({ ...item, type: e.target.value, attributes: {} })} + endpoint="/api/commands/types" + keyGetter={(it) => it.type} + titleGetter={(it) => t(prefixString('command', it.type))} + label={t('sharedType')} + variant="filled" + /> + {attributes.map((attribute) => ( + { + const updateItem = { ...item, attributes: { ...item.attributes } }; + updateItem.attributes[attribute.key] = e.target.value; + setItem(updateItem); + }} + label={attribute.name} + variant="filled" + /> + ))} + setItem({ ...item, textChannel: event.target.checked })} />} + label={t('commandSendSms')} + /> + + + )} + + ); +}; + +export default CommandPage; diff --git a/modern/src/settings/CommandsPage.js b/modern/src/settings/CommandsPage.js new file mode 100644 index 00000000..e8422467 --- /dev/null +++ b/modern/src/settings/CommandsPage.js @@ -0,0 +1,69 @@ +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'; +import { useEffectAsync } from '../reactHelper'; +import EditCollectionView from '../EditCollectionView'; +import OptionsLayout from './OptionsLayout'; +import { useTranslation } from '../LocalizationProvider'; +import { formatBoolean } from '../common/formatter'; +import { prefixString } from '../common/stringUtils'; + +const useStyles = makeStyles((theme) => ({ + columnAction: { + width: theme.spacing(1), + padding: theme.spacing(0, 1), + }, +})); + +const CommandsView = ({ updateTimestamp, onMenuClick }) => { + const classes = useStyles(); + const t = useTranslation(); + + const [items, setItems] = useState([]); + + useEffectAsync(async () => { + const response = await fetch('/api/commands'); + if (response.ok) { + setItems(await response.json()); + } + }, [updateTimestamp]); + + return ( + + + + + + {t('sharedDescription')} + {t('sharedType')} + {t('commandSendSms')} + + + + {items.map((item) => ( + + + onMenuClick(event.currentTarget, item.id)}> + + + + {item.description} + {t(prefixString('command', item.type))} + {formatBoolean(item.textChannel, t)} + + ))} + +
+
+ ); +}; + +const CommandsPage = () => ( + + + +); + +export default CommandsPage; diff --git a/modern/src/settings/ComputedAttributePage.js b/modern/src/settings/ComputedAttributePage.js index e8efd096..99bbfadb 100644 --- a/modern/src/settings/ComputedAttributePage.js +++ b/modern/src/settings/ComputedAttributePage.js @@ -40,7 +40,7 @@ const ComputedAttributePage = () => { }; return ( - + {item && ( diff --git a/modern/src/settings/OptionsLayout.js b/modern/src/settings/OptionsLayout.js index e588cafb..f2d8c5da 100644 --- a/modern/src/settings/OptionsLayout.js +++ b/modern/src/settings/OptionsLayout.js @@ -20,6 +20,7 @@ import BuildIcon from '@material-ui/icons/Build'; import PeopleIcon from '@material-ui/icons/People'; import BarChartIcon from '@material-ui/icons/BarChart'; import TodayIcon from '@material-ui/icons/Today'; +import ExitToAppIcon from '@material-ui/icons/ExitToApp'; import SideNav from '../components/SideNav'; import NavBar from '../components/NavBar'; @@ -79,14 +80,15 @@ const OptionsLayout = ({ children }) => { ], [t]); const mainRoutes = useMemo(() => [ + { name: t('sharedNotifications'), href: '/settings/notifications', icon: }, { name: t('settingsUser'), href: `/user/${userId}`, icon: }, { name: t('sharedGeofences'), href: '/geofences', icon: }, - { name: t('sharedNotifications'), href: '/settings/notifications', icon: }, { name: t('settingsGroups'), href: '/settings/groups', icon: }, { name: t('sharedDrivers'), href: '/settings/drivers', icon: }, { name: t('sharedCalendars'), href: '/settings/calendars', icon: }, { name: t('sharedComputedAttributes'), href: '/settings/attributes', icon: }, { name: t('sharedMaintenance'), href: '/settings/maintenances', icon: }, + { name: t('sharedSavedCommands'), href: '/settings/commands', icon: }, ], [t, userId]); const routes = useMemo(() => [...mainRoutes, ...(admin ? adminRoutes : [])], [mainRoutes, admin, adminRoutes]); -- cgit v1.2.3