diff --git a/.vscode/settings.json b/.vscode/settings.json
index 38fe48929..493bf41fe 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -84,5 +84,8 @@
"**/*.map",
"**/ArduinoJson/**"
],
- "cSpell.enableFiletypes": ["!cpp"]
+ "cSpell.enableFiletypes": [
+ "!cpp",
+ "!typescript"
+ ]
}
\ No newline at end of file
diff --git a/interface/src/AuthenticatedRouting.tsx b/interface/src/AuthenticatedRouting.tsx
index a05573e2a..689a325c2 100644
--- a/interface/src/AuthenticatedRouting.tsx
+++ b/interface/src/AuthenticatedRouting.tsx
@@ -1,7 +1,8 @@
+import { useContext, type FC } from 'react';
import { Navigate, Routes, Route } from 'react-router-dom';
import Help from './project/Help';
-import type { FC } from 'react';
-import { Layout, RequireAdmin } from 'components';
+import { Layout } from 'components';
+import { AuthenticatedContext } from 'contexts/authentication';
import Settings from 'framework/Settings';
import AccessPoint from 'framework/ap/AccessPoint';
import Mqtt from 'framework/mqtt/Mqtt';
@@ -18,49 +19,35 @@ import Devices from 'project/Devices';
import Scheduler from 'project/Scheduler';
import Sensors from 'project/Sensors';
-const AuthenticatedRouting: FC = () => (
-
-
- } />
- } />
-
- } />
- } />
- } />
-
- {/* TODO only show the rest here if admin */}
-
- } />
-
-
-
-
- }
- />
- } />
- } />
- } />
- } />
- } />
- } />
-
-
-
- }
- />
- } />
-
- } />
-
- } />
-
-
-);
+const AuthenticatedRouting: FC = () => {
+ const { me } = useContext(AuthenticatedContext);
+ return (
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ {me.admin && (
+ <>
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ >
+ )}
+
+
+ );
+};
export default AuthenticatedRouting;
diff --git a/interface/src/components/layout/LayoutMenu.tsx b/interface/src/components/layout/LayoutMenu.tsx
index 49c46cb4c..9a43749c1 100644
--- a/interface/src/components/layout/LayoutMenu.tsx
+++ b/interface/src/components/layout/LayoutMenu.tsx
@@ -2,7 +2,7 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import AssessmentIcon from '@mui/icons-material/Assessment';
import CategoryIcon from '@mui/icons-material/Category';
import ConstructionIcon from '@mui/icons-material/Construction';
-import InfoIcon from '@mui/icons-material/Info';
+import LiveHelpIcon from '@mui/icons-material/LiveHelp';
import MoreTimeIcon from '@mui/icons-material/MoreTime';
import PersonIcon from '@mui/icons-material/Person';
import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
@@ -73,14 +73,24 @@ const LayoutMenu: FC = () => {
-
-
-
+
+
+
-
+
diff --git a/interface/src/framework/ap/AccessPoint.tsx b/interface/src/framework/ap/AccessPoint.tsx
index 0aa655f84..e8b14bbf2 100644
--- a/interface/src/framework/ap/AccessPoint.tsx
+++ b/interface/src/framework/ap/AccessPoint.tsx
@@ -1,12 +1,10 @@
import { Tab } from '@mui/material';
-import { useContext } from 'react';
import { Navigate, Routes, Route } from 'react-router-dom';
import APSettingsForm from './APSettingsForm';
import APStatusForm from './APStatusForm';
import type { FC } from 'react';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
-import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
@@ -15,14 +13,12 @@ const AccessPoint: FC = () => {
useLayoutTitle(LL.ACCESS_POINT(0));
- const authenticatedContext = useContext(AuthenticatedContext);
-
const { routerTab } = useRouterTab();
return (
<>
-
+
diff --git a/interface/src/framework/mqtt/Mqtt.tsx b/interface/src/framework/mqtt/Mqtt.tsx
index 59779948f..0ef430924 100644
--- a/interface/src/framework/mqtt/Mqtt.tsx
+++ b/interface/src/framework/mqtt/Mqtt.tsx
@@ -1,12 +1,10 @@
import { Tab } from '@mui/material';
-import { useContext } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import MqttSettingsForm from './MqttSettingsForm';
import MqttStatusForm from './MqttStatusForm';
import type { FC } from 'react';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
-import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
@@ -15,13 +13,12 @@ const Mqtt: FC = () => {
useLayoutTitle('MQTT');
- const authenticatedContext = useContext(AuthenticatedContext);
const { routerTab } = useRouterTab();
return (
<>
-
+
diff --git a/interface/src/framework/network/NetworkConnection.tsx b/interface/src/framework/network/NetworkConnection.tsx
index 4d676324e..2e093ac3b 100644
--- a/interface/src/framework/network/NetworkConnection.tsx
+++ b/interface/src/framework/network/NetworkConnection.tsx
@@ -1,5 +1,5 @@
import { Tab } from '@mui/material';
-import { useCallback, useContext, useState } from 'react';
+import { useCallback, useState } from 'react';
import { Navigate, Routes, Route, useNavigate } from 'react-router-dom';
import NetworkSettingsForm from './NetworkSettingsForm';
import NetworkStatusForm from './NetworkStatusForm';
@@ -9,7 +9,6 @@ import type { FC } from 'react';
import type { WiFiNetwork } from 'types';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
-import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
const NetworkConnection: FC = () => {
@@ -18,7 +17,6 @@ const NetworkConnection: FC = () => {
const { routerTab } = useRouterTab();
- const authenticatedContext = useContext(AuthenticatedContext);
const navigate = useNavigate();
const [selectedNetwork, setSelectedNetwork] = useState();
@@ -44,8 +42,8 @@ const NetworkConnection: FC = () => {
}}
>
-
-
+
+
diff --git a/interface/src/framework/ntp/NTPStatusForm.tsx b/interface/src/framework/ntp/NTPStatusForm.tsx
index bf5122369..38f76be31 100644
--- a/interface/src/framework/ntp/NTPStatusForm.tsx
+++ b/interface/src/framework/ntp/NTPStatusForm.tsx
@@ -22,7 +22,7 @@ import {
Typography
} from '@mui/material';
import { useRequest } from 'alova';
-import { useContext, useState } from 'react';
+import { useState } from 'react';
import { toast } from 'react-toastify';
import type { Theme } from '@mui/material';
import type { FC } from 'react';
@@ -31,7 +31,6 @@ import type { NTPStatus } from 'types';
import { dialogStyle } from 'CustomTheme';
import * as NTPApi from 'api/ntp';
import { ButtonRow, FormLoader, SectionContent } from 'components';
-import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
import { NTPSyncStatus } from 'types';
@@ -59,7 +58,6 @@ const NTPStatusForm: FC = () => {
const [localTime, setLocalTime] = useState('');
const [settingTime, setSettingTime] = useState(false);
const [processing, setProcessing] = useState(false);
- const { me } = useContext(AuthenticatedContext);
const { LL } = useI18nContext();
@@ -201,7 +199,7 @@ const NTPStatusForm: FC = () => {
- {me.admin && data && !isNtpActive(data) && (
+ {data && !isNtpActive(data) && (
}>
diff --git a/interface/src/framework/ntp/NetworkTime.tsx b/interface/src/framework/ntp/NetworkTime.tsx
index f302a1273..1b3196e42 100644
--- a/interface/src/framework/ntp/NetworkTime.tsx
+++ b/interface/src/framework/ntp/NetworkTime.tsx
@@ -1,12 +1,10 @@
import { Tab } from '@mui/material';
-import { useContext } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import NTPSettingsForm from './NTPSettingsForm';
import NTPStatusForm from './NTPStatusForm';
import type { FC } from 'react';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
-import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
@@ -14,13 +12,12 @@ const NetworkTime: FC = () => {
const { LL } = useI18nContext();
useLayoutTitle('NTP');
- const authenticatedContext = useContext(AuthenticatedContext);
const { routerTab } = useRouterTab();
return (
<>
-
+
diff --git a/interface/src/framework/security/SecuritySettingsForm.tsx b/interface/src/framework/security/SecuritySettingsForm.tsx
index 6bad05516..dbcf27518 100644
--- a/interface/src/framework/security/SecuritySettingsForm.tsx
+++ b/interface/src/framework/security/SecuritySettingsForm.tsx
@@ -8,8 +8,8 @@ import type { FC } from 'react';
import type { SecuritySettings } from 'types';
import * as SecurityApi from 'api/security';
import { ButtonRow, FormLoader, MessageBox, SectionContent, ValidatedPasswordField, BlockNavigation } from 'components';
-import { AuthenticatedContext } from 'contexts/authentication';
+import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
import { updateValueDirty, useRest } from 'utils';
import { SECURITY_SETTINGS_VALIDATOR, validate } from 'validators';
diff --git a/interface/src/framework/system/SystemLog.tsx b/interface/src/framework/system/SystemLog.tsx
index d099872c6..91179265f 100644
--- a/interface/src/framework/system/SystemLog.tsx
+++ b/interface/src/framework/system/SystemLog.tsx
@@ -232,7 +232,7 @@ const SystemLog: FC = () => {
};
return (
-
+
{blocker ? : null}
{content()}
diff --git a/interface/src/framework/system/SystemStatusForm.tsx b/interface/src/framework/system/SystemStatusForm.tsx
index 27118e2e0..2efd72dcc 100644
--- a/interface/src/framework/system/SystemStatusForm.tsx
+++ b/interface/src/framework/system/SystemStatusForm.tsx
@@ -46,13 +46,14 @@ function formatNumber(num: number) {
const SystemStatusForm: FC = () => {
const { LL } = useI18nContext();
- const { me } = useContext(AuthenticatedContext);
const [confirmRestart, setConfirmRestart] = useState(false);
const [confirmFactoryReset, setConfirmFactoryReset] = useState(false);
const [processing, setProcessing] = useState(false);
const [restarting, setRestarting] = useState();
const [versionDialogOpen, setVersionDialogOpen] = useState(false);
+ const { me } = useContext(AuthenticatedContext);
+
const { send: restartCommand } = useRequest(SystemApi.restart(), {
immediate: false
});
@@ -187,7 +188,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -199,7 +200,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -208,7 +209,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -217,7 +218,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -240,7 +241,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -254,7 +255,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -268,7 +269,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -282,7 +283,7 @@ const SystemStatusForm: FC = () => {
-
+
@@ -296,7 +297,7 @@ const SystemStatusForm: FC = () => {
-
+
diff --git a/interface/src/framework/system/SystemStatusVersionDialog.tsx b/interface/src/framework/system/SystemStatusVersionDialog.tsx
index 1c7ab8876..54012c63d 100644
--- a/interface/src/framework/system/SystemStatusVersionDialog.tsx
+++ b/interface/src/framework/system/SystemStatusVersionDialog.tsx
@@ -31,7 +31,7 @@ const SystemStatusVersionDialog = ({ open, onClose, version, platform }: SystemS
const STABLE_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md';
const DEV_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md';
- const uploadURL = window.location.origin + '/system/upload';
+ const uploadURL = window.location.origin + '/settings/upload';
const connected = latestVersion && latestDevVersion;
diff --git a/interface/src/framework/system/UploadDownload.tsx b/interface/src/framework/system/UploadDownload.tsx
index fad58fd18..3726ec967 100644
--- a/interface/src/framework/system/UploadDownload.tsx
+++ b/interface/src/framework/system/UploadDownload.tsx
@@ -153,11 +153,6 @@ const UploadDownload: FC = () => {
{LL.DOWNLOAD(0)} {LL.SUPPORT_INFORMATION(1)}
-
-
- {LL.HELP_INFORMATION_4()}
-
-
}
variant="outlined"
@@ -216,7 +211,7 @@ const UploadDownload: FC = () => {
)}
>
);
- return {restarting ? : content()};
+ return {restarting ? : content()};
};
export default UploadDownload;
diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts
index 8aa1f9538..1d08d0772 100644
--- a/interface/src/i18n/en/index.ts
+++ b/interface/src/i18n/en/index.ts
@@ -155,7 +155,7 @@ const en: Translation = {
CUSTOMIZATIONS_HELP_4: 'exclude from MQTT and API',
CUSTOMIZATIONS_HELP_5: 'hide from Dashboard',
CUSTOMIZATIONS_HELP_6: 'remove from memory',
- SELECT_DEVICE: 'Select a device',
+ SELECT_DEVICE: 'select a device',
SET_ALL: 'set all',
OPTIONS: 'Options',
NAME: 'Name',
diff --git a/interface/src/project/DeviceIcon.tsx b/interface/src/project/DeviceIcon.tsx
index 85ae139f7..4362b7062 100644
--- a/interface/src/project/DeviceIcon.tsx
+++ b/interface/src/project/DeviceIcon.tsx
@@ -1,12 +1,13 @@
+import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
import { AiOutlineControl, AiOutlineGateway, AiOutlineAlert } from 'react-icons/ai';
import { CgSmartHomeBoiler } from 'react-icons/cg';
-
import { FaSolarPanel } from 'react-icons/fa';
import { GiHeatHaze } from 'react-icons/gi';
-import { MdThermostatAuto, MdOutlineSensors, MdOutlineExtension, MdOutlineDevices } from 'react-icons/md';
+import { MdThermostatAuto, MdOutlineSensors, MdOutlineDevices } from 'react-icons/md';
import { TiFlowSwitch } from 'react-icons/ti';
import { VscVmConnect } from 'react-icons/vsc';
import { DeviceType } from './types';
+
import type { FC } from 'react';
interface DeviceIconProps {
@@ -41,7 +42,7 @@ const DeviceIcon: FC = ({ type_id }) => {
case DeviceType.EXTENSION:
return ;
case DeviceType.CUSTOM:
- return ;
+ return ;
default:
return null;
}
diff --git a/interface/src/project/Devices.tsx b/interface/src/project/Devices.tsx
index 9fcf015e9..5ace3f3f2 100644
--- a/interface/src/project/Devices.tsx
+++ b/interface/src/project/Devices.tsx
@@ -33,7 +33,7 @@ import { useSort, SortToggleType } from '@table-library/react-table-library/sort
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { useRequest } from 'alova';
-import { useState, useContext, useEffect, useCallback, useLayoutEffect } from 'react';
+import { useState, useEffect, useCallback, useLayoutEffect } from 'react';
import { IconContext } from 'react-icons';
import { useNavigate } from 'react-router-dom';
@@ -50,12 +50,10 @@ import type { Device, DeviceValue } from './types';
import type { FC } from 'react';
import { dialogStyle } from 'CustomTheme';
import { ButtonRow, SectionContent, MessageBox, useLayoutTitle } from 'components';
-import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
const Devices: FC = () => {
- const { me } = useContext(AuthenticatedContext);
const { LL } = useI18nContext();
const [size, setSize] = useState([0, 0]);
const [selectedDeviceValue, setSelectedDeviceValue] = useState();
@@ -422,11 +420,8 @@ const Devices: FC = () => {
};
const renderCoreData = () => (
-
+
{!coreData.connected && }
- {/* {coreData.connected && coreData.devices.length === 0 && (
-
- )} */}
{coreData.connected && (
@@ -589,7 +584,7 @@ const Devices: FC = () => {
| {renderNameCell(dv)} |
{formatValue(LL, dv.v, dv.u)} |
- {dv.c && me.admin && !hasMask(dv.id, DeviceEntityMask.DV_READONLY) && (
+ {dv.c && !hasMask(dv.id, DeviceEntityMask.DV_READONLY) && (
showDeviceValue(dv)}>
{dv.v === '' && dv.c ? (
@@ -621,9 +616,7 @@ const Devices: FC = () => {
onSave={deviceValueDialogSave}
selectedItem={selectedDeviceValue}
writeable={
- me.admin &&
- selectedDeviceValue.c !== undefined &&
- !hasMask(selectedDeviceValue.id, DeviceEntityMask.DV_READONLY)
+ selectedDeviceValue.c !== undefined && !hasMask(selectedDeviceValue.id, DeviceEntityMask.DV_READONLY)
}
validator={deviceValueItemValidation(selectedDeviceValue)}
progress={submitting}
diff --git a/interface/src/project/EMSStatus.tsx b/interface/src/project/EMSStatus.tsx
index d4ccf9ed6..4bfc70bcf 100644
--- a/interface/src/project/EMSStatus.tsx
+++ b/interface/src/project/EMSStatus.tsx
@@ -206,7 +206,7 @@ const EMSStatus: FC = () => {
-
+
@@ -254,19 +254,20 @@ const EMSStatus: FC = () => {
{LL.REFRESH()}
-
-
- }
- variant="outlined"
- color="primary"
- disabled={!me.admin}
- onClick={() => setConfirmScan(true)}
- >
- {LL.SCAN_DEVICES()}
-
-
-
+ {me.admin && (
+
+
+ }
+ variant="outlined"
+ color="primary"
+ onClick={() => setConfirmScan(true)}
+ >
+ {LL.SCAN_DEVICES()}
+
+
+
+ )}
>
);
diff --git a/interface/src/project/Sensors.tsx b/interface/src/project/Sensors.tsx
index 233cf9eca..17364b6d8 100644
--- a/interface/src/project/Sensors.tsx
+++ b/interface/src/project/Sensors.tsx
@@ -8,7 +8,7 @@ import { useSort, SortToggleType } from '@table-library/react-table-library/sort
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { useRequest } from 'alova';
-import { useState, useContext, useEffect } from 'react';
+import { useState, useEffect, useContext } from 'react';
import { toast } from 'react-toastify';
@@ -27,12 +27,12 @@ import { useI18nContext } from 'i18n/i18n-react';
const Sensors: FC = () => {
const { LL } = useI18nContext();
- const { me } = useContext(AuthenticatedContext);
const [selectedTemperatureSensor, setSelectedTemperatureSensor] = useState();
const [selectedAnalogSensor, setSelectedAnalogSensor] = useState();
const [temperatureDialogOpen, setTemperatureDialogOpen] = useState(false);
const [analogDialogOpen, setAnalogDialogOpen] = useState(false);
const [creating, setCreating] = useState(false);
+ const { me } = useContext(AuthenticatedContext);
const { data: sensorData, send: fetchSensorData } = useRequest(() => EMSESP.readSensorData(), {
initialData: {
@@ -51,8 +51,6 @@ const Sensors: FC = () => {
immediate: false
});
- const isAdmin = me.admin;
-
const common_theme = useTheme({
BaseRow: `
font-size: 14px;
@@ -222,10 +220,8 @@ const Sensors: FC = () => {
}
const updateTemperatureSensor = (ts: TemperatureSensor) => {
- if (isAdmin) {
- setSelectedTemperatureSensor(ts);
- setTemperatureDialogOpen(true);
- }
+ setSelectedTemperatureSensor(ts);
+ setTemperatureDialogOpen(true);
};
const onTemperatureDialogClose = () => {
@@ -248,11 +244,9 @@ const Sensors: FC = () => {
};
const updateAnalogSensor = (as: AnalogSensor) => {
- if (isAdmin) {
- setCreating(false);
- setSelectedAnalogSensor(as);
- setAnalogDialogOpen(true);
- }
+ setCreating(false);
+ setSelectedAnalogSensor(as);
+ setAnalogDialogOpen(true);
};
const onAnalogDialogClose = () => {
@@ -453,7 +447,7 @@ const Sensors: FC = () => {
{LL.REFRESH()}
- {sensorData?.analog_enabled === true && (
+ {sensorData?.analog_enabled === true && me.admin && (
|