aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modern/src/common/attributes/useCommonUserAttributes.js4
-rw-r--r--modern/src/common/attributes/useServerAttributes.js8
-rw-r--r--modern/src/common/components/BottomMenu.js2
-rw-r--r--modern/src/common/util/permissions.js22
-rw-r--r--modern/src/login/LoginLayout.js38
-rw-r--r--modern/src/login/LoginPage.js25
-rw-r--r--modern/src/map/core/useMapStyles.js2
-rw-r--r--modern/src/map/overlay/useMapOverlays.js2
-rw-r--r--modern/src/settings/ServerPage.js4
-rw-r--r--modern/src/settings/components/SettingsMenu.js2
-rw-r--r--web/l10n/en.json1
11 files changed, 55 insertions, 55 deletions
diff --git a/modern/src/common/attributes/useCommonUserAttributes.js b/modern/src/common/attributes/useCommonUserAttributes.js
index 1409c5ac..ddd5d970 100644
--- a/modern/src/common/attributes/useCommonUserAttributes.js
+++ b/modern/src/common/attributes/useCommonUserAttributes.js
@@ -69,8 +69,4 @@ export default (t) => useMemo(() => ({
name: t('attributeWebMaxZoom'),
type: 'number',
},
- /* 'ui.hidePositionAttributes': {
- name: t('attributeUiHidePositionAttributes'),
- type: 'string',
- }, */
}), [t]);
diff --git a/modern/src/common/attributes/useServerAttributes.js b/modern/src/common/attributes/useServerAttributes.js
new file mode 100644
index 00000000..ba49e44d
--- /dev/null
+++ b/modern/src/common/attributes/useServerAttributes.js
@@ -0,0 +1,8 @@
+import { useMemo } from 'react';
+
+export default (t) => useMemo(() => ({
+ 'ui.disableLoginLanguage': {
+ name: t('attributeUiDisableLoginLanguage'),
+ type: 'boolean',
+ },
+}), [t]);
diff --git a/modern/src/common/components/BottomMenu.js b/modern/src/common/components/BottomMenu.js
index 282ae69e..37bdcf10 100644
--- a/modern/src/common/components/BottomMenu.js
+++ b/modern/src/common/components/BottomMenu.js
@@ -22,7 +22,7 @@ const BottomMenu = () => {
const t = useTranslation();
const readonly = useReadonly();
- const userId = useSelector((state) => state.session.user?.id);
+ const userId = useSelector((state) => state.session.user.id);
const socket = useSelector((state) => state.session.socket);
const [anchorEl, setAnchorEl] = useState(null);
diff --git a/modern/src/common/util/permissions.js b/modern/src/common/util/permissions.js
index 34aeb89d..c866c41e 100644
--- a/modern/src/common/util/permissions.js
+++ b/modern/src/common/util/permissions.js
@@ -1,28 +1,28 @@
import { useSelector } from 'react-redux';
export const useAdministrator = () => useSelector((state) => {
- const admin = state.session.user?.administrator;
+ const admin = state.session.user.administrator;
return admin;
});
export const useManager = () => useSelector((state) => {
- const admin = state.session.user?.administrator;
- const manager = (state.session.user?.userLimit || 0) > 0;
+ const admin = state.session.user.administrator;
+ const manager = (state.session.user.userLimit || 0) > 0;
return admin || manager;
});
export const useReadonly = () => useSelector((state) => {
- const admin = state.session.user?.administrator;
- const serverReadonly = state.session.server?.readonly;
- const userReadonly = state.session.user?.readonly;
+ const admin = state.session.user.administrator;
+ const serverReadonly = state.session.server.readonly;
+ const userReadonly = state.session.user.readonly;
return !admin && (serverReadonly || userReadonly);
});
export const useDeviceReadonly = () => useSelector((state) => {
- const admin = state.session.user?.administrator;
- const serverReadonly = state.session.server?.readonly;
- const userReadonly = state.session.user?.readonly;
- const serverDeviceReadonly = state.session.server?.deviceReadonly;
- const userDeviceReadonly = state.session.user?.deviceReadonly;
+ const admin = state.session.user.administrator;
+ const serverReadonly = state.session.server.readonly;
+ const userReadonly = state.session.user.readonly;
+ const serverDeviceReadonly = state.session.server.deviceReadonly;
+ const userDeviceReadonly = state.session.user.deviceReadonly;
return !admin && (serverReadonly || userReadonly || serverDeviceReadonly || userDeviceReadonly);
});
diff --git a/modern/src/login/LoginLayout.js b/modern/src/login/LoginLayout.js
index dff187c4..83a87500 100644
--- a/modern/src/login/LoginLayout.js
+++ b/modern/src/login/LoginLayout.js
@@ -40,12 +40,6 @@ const useStyles = makeStyles((theme) => ({
padding: theme.spacing(5),
width: '100%',
},
- attribution: {
- position: 'fixed',
- bottom: theme.spacing(1),
- right: theme.spacing(1.5),
- fontSize: 'x-small',
- },
}));
const LoginLayout = ({ children }) => {
@@ -53,26 +47,20 @@ const LoginLayout = ({ children }) => {
const theme = useTheme();
return (
- <>
- <main className={classes.root}>
- <div className={classes.sidebar}>
- {!useMediaQuery(theme.breakpoints.down('lg')) && (
- <svg height="64" width="240">
- <use xlinkHref={`${logoSvg}#img`} />
- </svg>
- )}
- </div>
- <Paper className={classes.paper}>
- <form className={classes.form}>
- {children}
- </form>
- </Paper>
- </main>
- <div className={classes.attribution}>
- Powered by&nbsp;
- <a href="https://www.traccar.org/">Traccar GPS Tracking System</a>
+ <main className={classes.root}>
+ <div className={classes.sidebar}>
+ {!useMediaQuery(theme.breakpoints.down('lg')) && (
+ <svg height="64" width="240">
+ <use xlinkHref={`${logoSvg}#img`} />
+ </svg>
+ )}
</div>
- </>
+ <Paper className={classes.paper}>
+ <form className={classes.form}>
+ {children}
+ </form>
+ </Paper>
+ </main>
);
};
diff --git a/modern/src/login/LoginPage.js b/modern/src/login/LoginPage.js
index 88a25d9d..c108f739 100644
--- a/modern/src/login/LoginPage.js
+++ b/modern/src/login/LoginPage.js
@@ -40,7 +40,8 @@ const useStyles = makeStyles((theme) => ({
},
resetPassword: {
cursor: 'pointer',
- textAlign: 'right',
+ textAlign: 'center',
+ marginTop: theme.spacing(2),
},
}));
@@ -59,11 +60,12 @@ const LoginPage = () => {
const [email, setEmail] = usePersistedState('loginEmail', '');
const [password, setPassword] = useState('');
- const registrationEnabled = useSelector((state) => state.session.server?.registration);
- const emailEnabled = useSelector((state) => state.session.server?.emailEnabled);
+ const registrationEnabled = useSelector((state) => state.session.server.registration);
+ const languageEnabled = useSelector((state) => !state.session.server.attributes['ui.disableLoginLanguage']);
+ const emailEnabled = useSelector((state) => state.session.server.emailEnabled);
const [announcementShown, setAnnouncementShown] = useState(false);
- const announcement = useSelector((state) => state.session.server?.announcement);
+ const announcement = useSelector((state) => state.session.server.announcement);
const handleSubmit = async (event) => {
event.preventDefault();
@@ -158,18 +160,21 @@ const LoginPage = () => {
>
{t('loginRegister')}
</Button>
- <FormControl fullWidth>
- <InputLabel>{t('loginLanguage')}</InputLabel>
- <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>
+ {languageEnabled && (
+ <FormControl fullWidth>
+ <InputLabel>{t('loginLanguage')}</InputLabel>
+ <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>
+ )}
</div>
{emailEnabled && (
<Link
onClick={() => navigate('/reset-password')}
className={classes.resetPassword}
underline="none"
+ variant="caption"
>
{t('loginReset')}
</Link>
diff --git a/modern/src/map/core/useMapStyles.js b/modern/src/map/core/useMapStyles.js
index 72f18ebc..78b3cdee 100644
--- a/modern/src/map/core/useMapStyles.js
+++ b/modern/src/map/core/useMapStyles.js
@@ -29,7 +29,7 @@ export default () => {
const tomTomKey = useAttributePreference('tomTomKey');
const hereKey = useAttributePreference('hereKey');
const mapboxAccessToken = useAttributePreference('mapboxAccessToken');
- const customMapUrl = useSelector((state) => state.session.server?.mapUrl);
+ const customMapUrl = useSelector((state) => state.session.server.mapUrl);
return [
{
diff --git a/modern/src/map/overlay/useMapOverlays.js b/modern/src/map/overlay/useMapOverlays.js
index e6311202..664054b8 100644
--- a/modern/src/map/overlay/useMapOverlays.js
+++ b/modern/src/map/overlay/useMapOverlays.js
@@ -18,7 +18,7 @@ export default () => {
const openWeatherKey = useAttributePreference('openWeatherKey');
const tomTomKey = useAttributePreference('tomTomKey');
const hereKey = useAttributePreference('hereKey');
- const customMapOverlay = useSelector((state) => state.session.server?.overlayUrl);
+ const customMapOverlay = useSelector((state) => state.session.server.overlayUrl);
return [
{
diff --git a/modern/src/settings/ServerPage.js b/modern/src/settings/ServerPage.js
index 26ef5bbf..90b854db 100644
--- a/modern/src/settings/ServerPage.js
+++ b/modern/src/settings/ServerPage.js
@@ -29,6 +29,7 @@ import SettingsMenu from './components/SettingsMenu';
import useCommonDeviceAttributes from '../common/attributes/useCommonDeviceAttributes';
import useCommonUserAttributes from '../common/attributes/useCommonUserAttributes';
import { useCatch } from '../reactHelper';
+import useServerAttributes from '../common/attributes/useServerAttributes';
const useStyles = makeStyles((theme) => ({
container: {
@@ -59,6 +60,7 @@ const ServerPage = () => {
const commonUserAttributes = useCommonUserAttributes(t);
const commonDeviceAttributes = useCommonDeviceAttributes(t);
+ const serverAttributes = useServerAttributes(t);
const original = useSelector((state) => state.session.server);
const [item, setItem] = useState({ ...original });
@@ -238,7 +240,7 @@ const ServerPage = () => {
<EditAttributesView
attributes={item.attributes}
setAttributes={(attributes) => setItem({ ...item, attributes })}
- definitions={{ ...commonUserAttributes, ...commonDeviceAttributes }}
+ definitions={{ ...commonUserAttributes, ...commonDeviceAttributes, ...serverAttributes }}
/>
</AccordionDetails>
</Accordion>
diff --git a/modern/src/settings/components/SettingsMenu.js b/modern/src/settings/components/SettingsMenu.js
index a37d5d1a..181cd74c 100644
--- a/modern/src/settings/components/SettingsMenu.js
+++ b/modern/src/settings/components/SettingsMenu.js
@@ -34,7 +34,7 @@ const SettingsMenu = () => {
const readonly = useReadonly();
const admin = useAdministrator();
const manager = useManager();
- const userId = useSelector((state) => state.session.user?.id);
+ const userId = useSelector((state) => state.session.user.id);
const features = useFeatures();
diff --git a/web/l10n/en.json b/web/l10n/en.json
index fc5a13a1..f0c51f96 100644
--- a/web/l10n/en.json
+++ b/web/l10n/en.json
@@ -121,6 +121,7 @@
"attributeUiDisableCalendars": "UI: Disable Calendars",
"attributeUiDisableMaintenance": "UI: Disable Maintenance",
"attributeUiHidePositionAttributes": "UI: Hide Position Attributes",
+ "attributeUiDisableLoginLanguage": "UI: Disable Login Language",
"attributeNotificationTokens": "Notification Tokens",
"errorTitle": "Error",
"errorGeneral": "Invalid parameters or constraints violation",