Migrated from redux to context API

This commit is contained in:
bourquecharles
2021-07-01 16:42:51 -04:00
parent f42b3d48d3
commit ae7200815d
40 changed files with 337 additions and 420 deletions

78
package-lock.json generated
View File

@@ -26,7 +26,6 @@
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-i18next": "^11.11.0", "react-i18next": "^11.11.0",
"react-paginate": "^7.1.3", "react-paginate": "^7.1.3",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3", "react-scripts": "^4.0.3",
"react-select": "^4.3.1", "react-select": "^4.3.1",
@@ -3210,15 +3209,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/html-minifier-terser": { "node_modules/@types/html-minifier-terser": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
@@ -3300,17 +3290,6 @@
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/@types/react-redux": {
"version": "7.1.16",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
"dependencies": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0",
"redux": "^4.0.0"
}
},
"node_modules/@types/react-transition-group": { "node_modules/@types/react-transition-group": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
@@ -16717,30 +16696,6 @@
"react": "^16.0.0 || ^17.0.0" "react": "^16.0.0 || ^17.0.0"
} }
}, },
"node_modules/react-redux": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
"integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==",
"dependencies": {
"@babel/runtime": "^7.12.1",
"@types/react-redux": "^7.1.16",
"hoist-non-react-statics": "^3.3.2",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-is": "^16.13.1"
},
"peerDependencies": {
"react": "^16.8.3 || ^17"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.8.3", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -24519,15 +24474,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"requires": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"@types/html-minifier-terser": { "@types/html-minifier-terser": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
@@ -24609,17 +24555,6 @@
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"@types/react-redux": {
"version": "7.1.16",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
"requires": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0",
"redux": "^4.0.0"
}
},
"@types/react-transition-group": { "@types/react-transition-group": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
@@ -35151,19 +35086,6 @@
"prop-types": "^15.6.1" "prop-types": "^15.6.1"
} }
}, },
"react-redux": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
"integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==",
"requires": {
"@babel/runtime": "^7.12.1",
"@types/react-redux": "^7.1.16",
"hoist-non-react-statics": "^3.3.2",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-is": "^16.13.1"
}
},
"react-refresh": { "react-refresh": {
"version": "0.8.3", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",

View File

@@ -21,7 +21,6 @@
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-i18next": "^11.11.0", "react-i18next": "^11.11.0",
"react-paginate": "^7.1.3", "react-paginate": "^7.1.3",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3", "react-scripts": "^4.0.3",
"react-select": "^4.3.1", "react-select": "^4.3.1",

View File

@@ -195,7 +195,7 @@
"trace": { "trace": {
"choose_network": "Netzwerk auswählen", "choose_network": "Netzwerk auswählen",
"directions": "Starten Sie eine Tcpdump auf diesem Geräts für eine bestimmte Dauer oder eine Anzahl von Paketen", "directions": "Starten Sie eine Tcpdump auf diesem Geräts für eine bestimmte Dauer oder eine Anzahl von Paketen",
"download_trace": "Klicke hier zum herunterladen", "download_trace": "Trace-Datei herunterladen",
"packets": "Pakete", "packets": "Pakete",
"title": "Tcpdump", "title": "Tcpdump",
"trace": "Spur", "trace": "Spur",

View File

@@ -195,7 +195,7 @@
"trace": { "trace": {
"choose_network": "Choose network", "choose_network": "Choose network",
"directions": "Launch a remote trace of this device for either a specific duration or a number of packets", "directions": "Launch a remote trace of this device for either a specific duration or a number of packets",
"download_trace": "Click here to download", "download_trace": "Download Trace File",
"packets": "Packets", "packets": "Packets",
"title": "Trace", "title": "Trace",
"trace": "Trace", "trace": "Trace",

View File

@@ -195,7 +195,7 @@
"trace": { "trace": {
"choose_network": "Elija la red", "choose_network": "Elija la red",
"directions": "Lanzar un rastreo remoto de este dispositivo por una duración específica o por una cantidad de paquetes", "directions": "Lanzar un rastreo remoto de este dispositivo por una duración específica o por una cantidad de paquetes",
"download_trace": "Haga click aquí para descargar", "download_trace": "Descargar archivo de seguimiento",
"packets": "Paquetes", "packets": "Paquetes",
"title": "Rastro", "title": "Rastro",
"trace": "Rastro", "trace": "Rastro",

View File

@@ -195,7 +195,7 @@
"trace": { "trace": {
"choose_network": "Choisir le réseau", "choose_network": "Choisir le réseau",
"directions": "Lancer une trace à distance de cet appareil pour une durée spécifique ou un nombre de paquets", "directions": "Lancer une trace à distance de cet appareil pour une durée spécifique ou un nombre de paquets",
"download_trace": "Cliquez ici pour télécharger", "download_trace": "Télécharger le fichier de trace",
"packets": "Paquets", "packets": "Paquets",
"title": "Trace", "title": "Trace",
"trace": "Trace", "trace": "Trace",

View File

@@ -195,7 +195,7 @@
"trace": { "trace": {
"choose_network": "Escolha a rede", "choose_network": "Escolha a rede",
"directions": "Lançar um rastreamento remoto deste dispositivo para uma duração específica ou um número de pacotes", "directions": "Lançar um rastreamento remoto deste dispositivo para uma duração específica ou um número de pacotes",
"download_trace": "Clique aqui para baixar", "download_trace": "Baixar arquivo de rastreamento",
"packets": "Pacotes", "packets": "Pacotes",
"title": "Vestígio", "title": "Vestígio",
"trace": "Vestígio", "trace": "Vestígio",

View File

@@ -1,7 +1,8 @@
import React, { useEffect } from 'react'; import React from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom'; import { HashRouter, Switch } from 'react-router-dom';
import 'scss/style.scss'; import 'scss/style.scss';
import { useSelector, useDispatch } from 'react-redux'; import Router from 'router';
import { AuthProvider } from 'contexts/AuthProvider';
const loading = ( const loading = (
<div className="pt-3 text-center"> <div className="pt-3 text-center">
@@ -9,32 +10,19 @@ const loading = (
</div> </div>
); );
const TheLayout = React.lazy(() => import('layout'));
const Login = React.lazy(() => import('pages/LoginPage'));
const App = () => { const App = () => {
const isLoggedIn = useSelector((state) => state.connected); const storageToken = sessionStorage.getItem('access_token');
const dispatch = useDispatch();
useEffect(() => {
const token = sessionStorage.getItem('access_token');
if (token !== undefined && token !== null) {
dispatch({ type: 'set', connected: true });
}
}, [dispatch]);
return ( return (
<HashRouter> <AuthProvider token={storageToken ?? ''}>
<React.Suspense fallback={loading}> <HashRouter>
<Switch> <React.Suspense fallback={loading}>
<Route <Switch>
path="/" <Router />
name="Devices" </Switch>
render={(props) => (isLoggedIn ? <TheLayout {...props} /> : <Login {...props} />)} </React.Suspense>
/> </HashRouter>
</Switch> </AuthProvider>
</React.Suspense>
</HashRouter>
); );
}; };

View File

@@ -16,10 +16,10 @@ import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import DatePicker from 'react-widgets/DatePicker'; import DatePicker from 'react-widgets/DatePicker';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { dateToUnix } from 'utils/helper'; import { dateToUnix } from 'utils/helper';
import 'react-widgets/styles.css'; import 'react-widgets/styles.css';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody'; import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
@@ -29,12 +29,13 @@ import styles from './index.module.scss';
const BlinkModal = ({ show, toggleModal }) => { const BlinkModal = ({ show, toggleModal }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [isNow, setIsNow] = useState(false); const [isNow, setIsNow] = useState(false);
const [waiting, setWaiting] = useState(false); const [waiting, setWaiting] = useState(false);
const [chosenDate, setChosenDate] = useState(new Date().toString()); const [chosenDate, setChosenDate] = useState(new Date().toString());
const [chosenPattern, setPattern] = useState('on'); const [chosenPattern, setPattern] = useState('on');
const [result, setResult] = useState(null); const [result, setResult] = useState(null);
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
const toggleNow = () => { const toggleNow = () => {
setIsNow(!isNow); setIsNow(!isNow);
@@ -57,12 +58,10 @@ const BlinkModal = ({ show, toggleModal }) => {
const doAction = () => { const doAction = () => {
setWaiting(true); setWaiting(true);
const token = getToken();
const utcDate = new Date(chosenDate); const utcDate = new Date(chosenDate);
const parameters = { const parameters = {
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
when: isNow ? 0 : dateToUnix(utcDate), when: isNow ? 0 : dateToUnix(utcDate),
pattern: chosenPattern, pattern: chosenPattern,
duration: 30, duration: 30,
@@ -70,11 +69,11 @@ const BlinkModal = ({ show, toggleModal }) => {
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance
.post(`/device/${encodeURIComponent(selectedDeviceId)}/leds`, parameters, { headers }) .post(`/device/${encodeURIComponent(deviceSerialNumber)}/leds`, parameters, { headers })
.then(() => { .then(() => {
setResult('success'); setResult('success');
}) })
@@ -102,42 +101,42 @@ const BlinkModal = ({ show, toggleModal }) => {
<CLabel>{t('blink.pattern')}</CLabel> <CLabel>{t('blink.pattern')}</CLabel>
</CCol> </CCol>
<CCol> <CCol>
<CFormGroup variant="custom-radio" onClick={() => setPattern('on')} inline> <CFormGroup variant="custom-radio" onClick={() => setPattern('on')} inline>
<CInputRadio <CInputRadio
custom custom
defaultChecked={chosenPattern === 'on'} defaultChecked={chosenPattern === 'on'}
id="radio1" id="radio1"
name="radios" name="radios"
value="option1" value="option1"
/> />
<CLabel variant="custom-checkbox" htmlFor="radio1"> <CLabel variant="custom-checkbox" htmlFor="radio1">
{t('common.on')} {t('common.on')}
</CLabel> </CLabel>
</CFormGroup> </CFormGroup>
<CFormGroup variant="custom-radio" onClick={() => setPattern('off')} inline> <CFormGroup variant="custom-radio" onClick={() => setPattern('off')} inline>
<CInputRadio <CInputRadio
custom custom
defaultChecked={chosenPattern === 'off'} defaultChecked={chosenPattern === 'off'}
id="radio2" id="radio2"
name="radios" name="radios"
value="option2" value="option2"
/> />
<CLabel variant="custom-checkbox" htmlFor="radio2"> <CLabel variant="custom-checkbox" htmlFor="radio2">
{t('common.off')} {t('common.off')}
</CLabel> </CLabel>
</CFormGroup> </CFormGroup>
<CFormGroup variant="custom-radio" onClick={() => setPattern('blink')} inline> <CFormGroup variant="custom-radio" onClick={() => setPattern('blink')} inline>
<CInputRadio <CInputRadio
custom custom
defaultChecked={chosenPattern === 'blink'} defaultChecked={chosenPattern === 'blink'}
id="radio3" id="radio3"
name="radios" name="radios"
value="option3" value="option3"
/> />
<CLabel variant="custom-checkbox" htmlFor="radio3"> <CLabel variant="custom-checkbox" htmlFor="radio3">
{t('blink.blink')} {t('blink.blink')}
</CLabel> </CLabel>
</CFormGroup> </CFormGroup>
</CCol> </CCol>
</CFormGroup> </CFormGroup>
<CRow className={styles.spacedRow}> <CRow className={styles.spacedRow}>

View File

@@ -14,10 +14,10 @@ import {
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import DatePicker from 'react-widgets/DatePicker'; import DatePicker from 'react-widgets/DatePicker';
import { cilCloudDownload, cilSync, cilCalendarCheck } from '@coreui/icons'; import { cilCloudDownload, cilSync, cilCalendarCheck } from '@coreui/icons';
import PropTypes from 'prop-types';
import { prettyDate, dateToUnix } from 'utils/helper'; import { prettyDate, dateToUnix } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import ConfirmModal from 'components/ConfirmModal'; import ConfirmModal from 'components/ConfirmModal';
import LoadingButton from 'components/LoadingButton'; import LoadingButton from 'components/LoadingButton';
@@ -25,8 +25,10 @@ import WifiScanResultModalWidget from 'components/WifiScanResultModal';
import DeviceCommandsCollapse from './DeviceCommandsCollapse'; import DeviceCommandsCollapse from './DeviceCommandsCollapse';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeviceCommands = ({ selectedDeviceId }) => { const DeviceCommands = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
// Wifiscan result related // Wifiscan result related
const [chosenWifiScan, setChosenWifiScan] = useState(null); const [chosenWifiScan, setChosenWifiScan] = useState(null);
const [showScanModal, setShowScanModal] = useState(false); const [showScanModal, setShowScanModal] = useState(false);
@@ -90,7 +92,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
params: { params: {
limit: commandLimit, limit: commandLimit,
@@ -107,7 +109,10 @@ const DeviceCommands = ({ selectedDeviceId }) => {
} }
axiosInstance axiosInstance
.get(`/commands?serialNumber=${encodeURIComponent(selectedDeviceId)}${extraParams}`, options) .get(
`/commands?serialNumber=${encodeURIComponent(deviceSerialNumber)}${extraParams}`,
options,
)
.then((response) => { .then((response) => {
setCommands(response.data.commands); setCommands(response.data.commands);
}) })
@@ -122,13 +127,13 @@ const DeviceCommands = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/octet-stream', Accept: 'application/octet-stream',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
responseType: 'arraybuffer', responseType: 'arraybuffer',
}; };
axiosInstance axiosInstance
.get(`/file/${uuid}?serialNumber=${selectedDeviceId}`, options) .get(`/file/${uuid}?serialNumber=${deviceSerialNumber}`, options)
.then((response) => { .then((response) => {
const blob = new Blob([response.data], { type: 'application/octet-stream' }); const blob = new Blob([response.data], { type: 'application/octet-stream' });
const link = document.createElement('a'); const link = document.createElement('a');
@@ -145,7 +150,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };
return axiosInstance return axiosInstance
@@ -231,12 +236,12 @@ const DeviceCommands = ({ selectedDeviceId }) => {
]; ];
useEffect(() => { useEffect(() => {
if (selectedDeviceId && start !== '' && end !== '') { if (deviceSerialNumber && start !== '' && end !== '') {
getCommands(); getCommands();
} else if (selectedDeviceId && start === '' && end === '') { } else if (deviceSerialNumber && start === '' && end === '') {
getCommands(); getCommands();
} }
}, [selectedDeviceId, start, end]); }, [deviceSerialNumber, start, end]);
useEffect(() => { useEffect(() => {
eventBus.on('actionCompleted', () => refreshCommands()); eventBus.on('actionCompleted', () => refreshCommands());
@@ -247,7 +252,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (selectedDeviceId) { if (deviceSerialNumber) {
setCommandLimit(25); setCommandLimit(25);
setLoadingMore(false); setLoadingMore(false);
setShowLoadingMore(true); setShowLoadingMore(true);
@@ -255,7 +260,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
setEnd(''); setEnd('');
getCommands(); getCommands();
} }
}, [selectedDeviceId]); }, [deviceSerialNumber]);
useEffect(() => { useEffect(() => {
if (commandLimit !== 25) { if (commandLimit !== 25) {
@@ -446,8 +451,4 @@ const DeviceCommands = ({ selectedDeviceId }) => {
); );
}; };
DeviceCommands.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default DeviceCommands; export default DeviceCommands;

View File

@@ -16,9 +16,9 @@ import {
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import 'react-widgets/styles.css'; import 'react-widgets/styles.css';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import { checkIfJson } from 'utils/helper'; import { checkIfJson } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
@@ -27,6 +27,8 @@ import styles from './index.module.scss';
const ConfigureModal = ({ show, toggleModal }) => { const ConfigureModal = ({ show, toggleModal }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [hadSuccess, setHadSuccess] = useState(false); const [hadSuccess, setHadSuccess] = useState(false);
const [hadFailure, setHadFailure] = useState(false); const [hadFailure, setHadFailure] = useState(false);
const [doingNow, setDoingNow] = useState(false); const [doingNow, setDoingNow] = useState(false);
@@ -36,7 +38,7 @@ const ConfigureModal = ({ show, toggleModal }) => {
const [checkingIfSure, setCheckingIfSure] = useState(false); const [checkingIfSure, setCheckingIfSure] = useState(false);
const [errorJson, setErrorJson] = useState(false); const [errorJson, setErrorJson] = useState(false);
const [inputKey, setInputKey] = useState(0); const [inputKey, setInputKey] = useState(0);
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
let fileReader; let fileReader;
const confirmingIfSure = () => { const confirmingIfSure = () => {
@@ -69,10 +71,8 @@ const ConfigureModal = ({ show, toggleModal }) => {
setHadSuccess(false); setHadSuccess(false);
setWaiting(true); setWaiting(true);
const token = getToken();
const parameters = { const parameters = {
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
when: 0, when: 0,
UUID: 1, UUID: 1,
configuration: JSON.parse(newConfig), configuration: JSON.parse(newConfig),
@@ -80,11 +80,11 @@ const ConfigureModal = ({ show, toggleModal }) => {
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance
.post(`/device/${encodeURIComponent(selectedDeviceId)}/configure`, parameters, { headers }) .post(`/device/${encodeURIComponent(deviceSerialNumber)}/configure`, parameters, { headers })
.then(() => { .then(() => {
setHadSuccess(true); setHadSuccess(true);
}) })

View File

@@ -6,12 +6,15 @@ import PropTypes from 'prop-types';
import ConfirmFooter from 'components/ConfirmFooter'; import ConfirmFooter from 'components/ConfirmFooter';
import { dateToUnix } from 'utils/helper'; import { dateToUnix } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper'; import { useDevice } from 'contexts/DeviceProvider';
import { useAuth } from 'contexts/AuthProvider';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeleteLogModal = ({ serialNumber, show, toggle, object }) => { const DeleteLogModal = ({ show, toggle, object }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [maxDate, setMaxDate] = useState(new Date().toString()); const [maxDate, setMaxDate] = useState(new Date().toString());
@@ -27,14 +30,14 @@ const DeleteLogModal = ({ serialNumber, show, toggle, object }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
params: { params: {
endDate: dateToUnix(maxDate), endDate: dateToUnix(maxDate),
}, },
}; };
return axiosInstance return axiosInstance
.delete(`/device/${serialNumber}/${object}`, options) .delete(`/device/${deviceSerialNumber}/${object}`, options)
.then(() => {}) .then(() => {})
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {
@@ -94,7 +97,6 @@ DeleteLogModal.propTypes = {
show: PropTypes.bool.isRequired, show: PropTypes.bool.isRequired,
toggle: PropTypes.func.isRequired, toggle: PropTypes.func.isRequired,
object: PropTypes.string.isRequired, object: PropTypes.string.isRequired,
serialNumber: PropTypes.string.isRequired,
}; };
export default DeleteLogModal; export default DeleteLogModal;

View File

@@ -1,9 +1,9 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import { CButton, CCard, CCardHeader, CCardBody, CRow, CCol } from '@coreui/react'; import { CButton, CCard, CCardHeader, CCardBody, CRow, CCol } from '@coreui/react';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import LoadingButton from 'components/LoadingButton'; import LoadingButton from 'components/LoadingButton';
import RebootModal from 'components/RebootModal'; import RebootModal from 'components/RebootModal';
import FirmwareUpgradeModal from 'components/FirmwareUpgradeModal'; import FirmwareUpgradeModal from 'components/FirmwareUpgradeModal';
@@ -15,8 +15,10 @@ import FactoryResetModal from 'components/FactoryResetModal';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeviceActions = ({ selectedDeviceId }) => { const DeviceActions = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [showRebootModal, setShowRebootModal] = useState(false); const [showRebootModal, setShowRebootModal] = useState(false);
const [showBlinkModal, setShowBlinkModal] = useState(false); const [showBlinkModal, setShowBlinkModal] = useState(false);
const [showUpgradeModal, setShowUpgradeModal] = useState(false); const [showUpgradeModal, setShowUpgradeModal] = useState(false);
@@ -59,12 +61,12 @@ const DeviceActions = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };
axiosInstance axiosInstance
.get(`/device/${encodeURIComponent(selectedDeviceId)}/rtty`, options) .get(`/device/${encodeURIComponent(deviceSerialNumber)}/rtty`, options)
.then((response) => { .then((response) => {
const url = `https://${response.data.server}:${response.data.viewport}/connect/${response.data.connectionId}`; const url = `https://${response.data.server}:${response.data.viewport}/connect/${response.data.connectionId}`;
const newWindow = window.open(url, '_blank', 'noopener,noreferrer'); const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
@@ -145,8 +147,4 @@ const DeviceActions = ({ selectedDeviceId }) => {
); );
}; };
DeviceActions.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default DeviceActions; export default DeviceActions;

View File

@@ -14,17 +14,19 @@ import {
CPopover, CPopover,
} from '@coreui/react'; } from '@coreui/react';
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import PropTypes from 'prop-types';
import { cilWindowMaximize } from '@coreui/icons'; import { cilWindowMaximize } from '@coreui/icons';
import { prettyDate } from 'utils/helper'; import { prettyDate } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import CopyToClipboardButton from 'components/CopyToClipboardButton'; import CopyToClipboardButton from 'components/CopyToClipboardButton';
import DeviceConfigurationModal from './DeviceConfigurationModal'; import DeviceConfigurationModal from './DeviceConfigurationModal';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeviceConfiguration = ({ selectedDeviceId }) => { const DeviceConfiguration = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [collapse, setCollapse] = useState(false); const [collapse, setCollapse] = useState(false);
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const [device, setDevice] = useState(null); const [device, setDevice] = useState(null);
@@ -42,12 +44,12 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };
axiosInstance axiosInstance
.get(`/device/${encodeURIComponent(selectedDeviceId)}`, options) .get(`/device/${encodeURIComponent(deviceSerialNumber)}`, options)
.then((response) => { .then((response) => {
setDevice(response.data); setDevice(response.data);
}) })
@@ -55,8 +57,8 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
}; };
useEffect(() => { useEffect(() => {
if (selectedDeviceId) getDevice(); if (deviceSerialNumber) getDevice();
}, [selectedDeviceId]); }, [deviceSerialNumber]);
if (device) { if (device) {
return ( return (
@@ -206,8 +208,4 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
); );
}; };
DeviceConfiguration.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default DeviceConfiguration; export default DeviceConfiguration;

View File

@@ -15,17 +15,19 @@ import {
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import DatePicker from 'react-widgets/DatePicker'; import DatePicker from 'react-widgets/DatePicker';
import PropTypes from 'prop-types';
import { prettyDate, dateToUnix } from 'utils/helper'; import { prettyDate, dateToUnix } from 'utils/helper';
import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import LoadingButton from 'components/LoadingButton'; import LoadingButton from 'components/LoadingButton';
import DeleteLogModal from 'components/DeleteLogModal'; import DeleteLogModal from 'components/DeleteLogModal';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeviceHealth = ({ selectedDeviceId }) => { const DeviceHealth = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [collapse, setCollapse] = useState(false); const [collapse, setCollapse] = useState(false);
const [details, setDetails] = useState([]); const [details, setDetails] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -68,7 +70,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
params: { params: {
limit: logLimit, limit: logLimit,
@@ -85,7 +87,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
} }
axiosInstance axiosInstance
.get(`/device/${encodeURIComponent(selectedDeviceId)}/healthchecks${extraParams}`, options) .get(`/device/${encodeURIComponent(deviceSerialNumber)}/healthchecks${extraParams}`, options)
.then((response) => { .then((response) => {
setHealthChecks(response.data.values); setHealthChecks(response.data.values);
}) })
@@ -128,7 +130,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
]; ];
useEffect(() => { useEffect(() => {
if (selectedDeviceId) { if (deviceSerialNumber) {
setLogLimit(25); setLogLimit(25);
setLoadingMore(false); setLoadingMore(false);
setShowLoadingMore(true); setShowLoadingMore(true);
@@ -136,7 +138,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
setEnd(''); setEnd('');
getDeviceHealth(); getDeviceHealth();
} }
}, [selectedDeviceId]); }, [deviceSerialNumber]);
useEffect(() => { useEffect(() => {
if (logLimit !== 25) { if (logLimit !== 25) {
@@ -168,12 +170,12 @@ const DeviceHealth = ({ selectedDeviceId }) => {
}, [healthChecks]); }, [healthChecks]);
useEffect(() => { useEffect(() => {
if (selectedDeviceId && start !== '' && end !== '') { if (deviceSerialNumber && start !== '' && end !== '') {
getDeviceHealth(); getDeviceHealth();
} else if (selectedDeviceId && start === '' && end === '') { } else if (deviceSerialNumber && start === '' && end === '') {
getDeviceHealth(); getDeviceHealth();
} }
}, [start, end, selectedDeviceId]); }, [start, end, deviceSerialNumber]);
useEffect(() => { useEffect(() => {
eventBus.on('deletedHealth', () => getDeviceHealth()); eventBus.on('deletedHealth', () => getDeviceHealth());
@@ -281,7 +283,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
/> />
</CButton> </CButton>
<DeleteLogModal <DeleteLogModal
serialNumber={selectedDeviceId} serialNumber={deviceSerialNumber}
object="healthchecks" object="healthchecks"
show={showDeleteModal} show={showDeleteModal}
toggle={toggleDeleteModal} toggle={toggleDeleteModal}
@@ -292,8 +294,4 @@ const DeviceHealth = ({ selectedDeviceId }) => {
); );
}; };
DeviceHealth.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default DeviceHealth; export default DeviceHealth;

View File

@@ -17,7 +17,7 @@ import Select from 'react-select';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { cilSync, cilInfo, cilBadge, cilBan } from '@coreui/icons'; import { cilSync, cilInfo, cilBadge, cilBan } from '@coreui/icons';
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { cleanBytesString } from 'utils/helper'; import { cleanBytesString } from 'utils/helper';
import meshIcon from 'assets/icons/Mesh.png'; import meshIcon from 'assets/icons/Mesh.png';
@@ -29,6 +29,7 @@ import styles from './index.module.scss';
const DeviceList = () => { const DeviceList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const [loadedSerials, setLoadedSerials] = useState(false); const [loadedSerials, setLoadedSerials] = useState(false);
const [serialNumbers, setSerialNumbers] = useState([]); const [serialNumbers, setSerialNumbers] = useState([]);
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
@@ -38,12 +39,11 @@ const DeviceList = () => {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const getSerialNumbers = () => { const getSerialNumbers = () => {
const token = getToken();
setLoading(true); setLoading(true);
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance
@@ -60,12 +60,11 @@ const DeviceList = () => {
}; };
const getDeviceInformation = () => { const getDeviceInformation = () => {
const token = getToken();
setLoading(true); setLoading(true);
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
const startIndex = page * devicesPerPage; const startIndex = page * devicesPerPage;
@@ -89,12 +88,11 @@ const DeviceList = () => {
}; };
const refreshDevice = (serialNumber) => { const refreshDevice = (serialNumber) => {
const token = getToken();
setLoading(true); setLoading(true);
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance

View File

@@ -14,17 +14,19 @@ import {
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import DatePicker from 'react-widgets/DatePicker'; import DatePicker from 'react-widgets/DatePicker';
import PropTypes from 'prop-types';
import { prettyDate, dateToUnix } from 'utils/helper'; import { prettyDate, dateToUnix } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import LoadingButton from 'components/LoadingButton'; import LoadingButton from 'components/LoadingButton';
import DeleteLogModal from 'components/DeleteLogModal'; import DeleteLogModal from 'components/DeleteLogModal';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeviceLogs = ({ selectedDeviceId }) => { const DeviceLogs = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [collapse, setCollapse] = useState(false); const [collapse, setCollapse] = useState(false);
const [details, setDetails] = useState([]); const [details, setDetails] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -65,7 +67,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
params: { params: {
limit: logLimit, limit: logLimit,
@@ -82,7 +84,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
} }
axiosInstance axiosInstance
.get(`/device/${encodeURIComponent(selectedDeviceId)}/logs${extraParams}`, options) .get(`/device/${encodeURIComponent(deviceSerialNumber)}/logs${extraParams}`, options)
.then((response) => { .then((response) => {
setLogs(response.data.values); setLogs(response.data.values);
}) })
@@ -125,7 +127,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
]; ];
useEffect(() => { useEffect(() => {
if (selectedDeviceId) { if (deviceSerialNumber) {
setLogLimit(25); setLogLimit(25);
setLoadingMore(false); setLoadingMore(false);
setShowLoadingMore(true); setShowLoadingMore(true);
@@ -133,7 +135,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
setEnd(''); setEnd('');
getLogs(); getLogs();
} }
}, [selectedDeviceId]); }, [deviceSerialNumber]);
useEffect(() => { useEffect(() => {
if (logLimit !== 25) { if (logLimit !== 25) {
@@ -150,12 +152,12 @@ const DeviceLogs = ({ selectedDeviceId }) => {
}, [logs]); }, [logs]);
useEffect(() => { useEffect(() => {
if (selectedDeviceId && start !== '' && end !== '') { if (deviceSerialNumber && start !== '' && end !== '') {
getLogs(); getLogs();
} else if (selectedDeviceId && start === '' && end === '') { } else if (deviceSerialNumber && start === '' && end === '') {
getLogs(); getLogs();
} }
}, [start, end, selectedDeviceId]); }, [start, end, deviceSerialNumber]);
useEffect(() => { useEffect(() => {
eventBus.on('deletedLogs', () => getLogs()); eventBus.on('deletedLogs', () => getLogs());
@@ -258,7 +260,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
} }
/> />
<DeleteLogModal <DeleteLogModal
serialNumber={selectedDeviceId} serialNumber={deviceSerialNumber}
object="logs" object="logs"
show={showDeleteModal} show={showDeleteModal}
toggle={toggleDeleteModal} toggle={toggleDeleteModal}
@@ -267,8 +269,4 @@ const DeviceLogs = ({ selectedDeviceId }) => {
); );
}; };
DeviceLogs.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default DeviceLogs; export default DeviceLogs;

View File

@@ -13,18 +13,20 @@ import {
CSpinner, CSpinner,
} from '@coreui/react'; } from '@coreui/react';
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import { cilSync } from '@coreui/icons'; import { cilSync } from '@coreui/icons';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper';
import { prettyDate, secondsToDetailed } from 'utils/helper'; import { prettyDate, secondsToDetailed } from 'utils/helper';
import MemoryBar from './MemoryBar'; import MemoryBar from './MemoryBar';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeviceStatusCard = ({ selectedDeviceId }) => { const DeviceStatusCard = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [lastStats, setLastStats] = useState(null); const [lastStats, setLastStats] = useState(null);
const [status, setStatus] = useState(null); const [status, setStatus] = useState(null);
const [error, setError] = useState(false); const [error, setError] = useState(false);
@@ -40,16 +42,16 @@ const DeviceStatusCard = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };
const lastStatsRequest = axiosInstance.get( const lastStatsRequest = axiosInstance.get(
`/device/${encodeURIComponent(selectedDeviceId)}/statistics?lastOnly=true`, `/device/${encodeURIComponent(deviceSerialNumber)}/statistics?lastOnly=true`,
options, options,
); );
const statusRequest = axiosInstance.get( const statusRequest = axiosInstance.get(
`/device/${encodeURIComponent(selectedDeviceId)}/status`, `/device/${encodeURIComponent(deviceSerialNumber)}/status`,
options, options,
); );
@@ -68,8 +70,8 @@ const DeviceStatusCard = ({ selectedDeviceId }) => {
useEffect(() => { useEffect(() => {
setError(false); setError(false);
if (selectedDeviceId) getData(); if (deviceSerialNumber) getData();
}, [selectedDeviceId]); }, [deviceSerialNumber]);
if (!error) { if (!error) {
return ( return (
@@ -78,7 +80,7 @@ const DeviceStatusCard = ({ selectedDeviceId }) => {
<CRow> <CRow>
<CCol> <CCol>
<div className="text-value-lg"> <div className="text-value-lg">
{t('status.title', { serialNumber: selectedDeviceId })} {t('status.title', { serialNumber: deviceSerialNumber })}
</div> </div>
</CCol> </CCol>
<CCol> <CCol>
@@ -152,10 +154,14 @@ const DeviceStatusCard = ({ selectedDeviceId }) => {
</CRow> </CRow>
<CRow className={styles.spacedRow}> <CRow className={styles.spacedRow}>
<CCol md="5">{t('status.memory')} :</CCol> <CCol md="5">{t('status.memory')} :</CCol>
<CCol xs="9" md="6" style={{paddingTop: '5px'}}> <CCol xs="9" md="6" style={{ paddingTop: '5px' }}>
<MemoryBar <MemoryBar
usedBytes={lastStats?.unit?.memory?.total - lastStats?.unit?.memory?.free} usedBytes={
totalBytes={lastStats?.unit?.memory?.total} lastStats?.unit?.memory?.total && lastStats?.unit?.memory?.free
? lastStats?.unit?.memory?.total - lastStats?.unit?.memory?.free
: 0
}
totalBytes={lastStats?.unit?.memory?.total ?? 0}
/> />
</CCol> </CCol>
</CRow> </CRow>
@@ -172,7 +178,7 @@ const DeviceStatusCard = ({ selectedDeviceId }) => {
<CRow> <CRow>
<CCol> <CCol>
<div className="text-value-lg"> <div className="text-value-lg">
{t('status.title', { serialNumber: selectedDeviceId })} {t('status.title', { serialNumber: deviceSerialNumber })}
</div> </div>
</CCol> </CCol>
</CRow> </CRow>
@@ -186,8 +192,4 @@ const DeviceStatusCard = ({ selectedDeviceId }) => {
); );
}; };
DeviceStatusCard.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default React.memo(DeviceStatusCard); export default React.memo(DeviceStatusCard);

View File

@@ -14,15 +14,17 @@ import {
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import 'react-widgets/styles.css'; import 'react-widgets/styles.css';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody'; import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
import styles from './index.module.scss'; import styles from './index.module.scss';
const ConfigureModal = ({ show, toggleModal }) => { const ConfigureModal = ({ show, toggleModal }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [hadSuccess, setHadSuccess] = useState(false); const [hadSuccess, setHadSuccess] = useState(false);
const [hadFailure, setHadFailure] = useState(false); const [hadFailure, setHadFailure] = useState(false);
const [doingNow, setDoingNow] = useState(false); const [doingNow, setDoingNow] = useState(false);
@@ -30,7 +32,6 @@ const ConfigureModal = ({ show, toggleModal }) => {
const [keepRedirector, setKeepRedirector] = useState(true); const [keepRedirector, setKeepRedirector] = useState(true);
const [responseBody, setResponseBody] = useState(''); const [responseBody, setResponseBody] = useState('');
const [checkingIfSure, setCheckingIfSure] = useState(false); const [checkingIfSure, setCheckingIfSure] = useState(false);
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
const toggleRedirector = () => { const toggleRedirector = () => {
setKeepRedirector(!keepRedirector); setKeepRedirector(!keepRedirector);
@@ -54,17 +55,17 @@ const ConfigureModal = ({ show, toggleModal }) => {
setWaiting(true); setWaiting(true);
const parameters = { const parameters = {
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
keepRedirector, keepRedirector,
}; };
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance
.post(`/device/${encodeURIComponent(selectedDeviceId)}/factory`, parameters, { headers }) .post(`/device/${encodeURIComponent(deviceSerialNumber)}/factory`, parameters, { headers })
.then(() => { .then(() => {
setHadSuccess(true); setHadSuccess(true);
}) })

View File

@@ -3,11 +3,12 @@ import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { CModalBody } from '@coreui/react'; import { CModalBody } from '@coreui/react';
import { v4 as createUuid } from 'uuid'; import { v4 as createUuid } from 'uuid';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
const UpgradeWaitingBody = ({ serialNumber }) => { const UpgradeWaitingBody = ({ serialNumber }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const [currentStep, setCurrentStep] = useState(0); const [currentStep, setCurrentStep] = useState(0);
const [secondsElapsed, setSecondsElapsed] = useState(0); const [secondsElapsed, setSecondsElapsed] = useState(0);
const [labelsToShow, setLabelsToShow] = useState(['upgrade.command_submitted']); const [labelsToShow, setLabelsToShow] = useState(['upgrade.command_submitted']);
@@ -16,7 +17,7 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };
@@ -30,7 +31,7 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };

View File

@@ -15,10 +15,10 @@ import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import DatePicker from 'react-widgets/DatePicker'; import DatePicker from 'react-widgets/DatePicker';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { dateToUnix } from 'utils/helper'; import { dateToUnix } from 'utils/helper';
import 'react-widgets/styles.css'; import 'react-widgets/styles.css';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import getDeviceConnection from 'utils/deviceHelper'; import getDeviceConnection from 'utils/deviceHelper';
@@ -28,6 +28,8 @@ import UpgradeWaitingBody from './UpgradeWaitingBody';
const FirmwareUpgradeModal = ({ show, toggleModal }) => { const FirmwareUpgradeModal = ({ show, toggleModal }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [isNow, setIsNow] = useState(true); const [isNow, setIsNow] = useState(true);
const [waitForUpgrade, setWaitForUpgrade] = useState(false); const [waitForUpgrade, setWaitForUpgrade] = useState(false);
const [date, setDate] = useState(new Date().toString()); const [date, setDate] = useState(new Date().toString());
@@ -39,7 +41,6 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
const [waitingForUpgrade, setWaitingForUpgrade] = useState(false); const [waitingForUpgrade, setWaitingForUpgrade] = useState(false);
const [showWaitingConsole, setShowWaitingConsole] = useState(false); const [showWaitingConsole, setShowWaitingConsole] = useState(false);
const [deviceConnected, setDeviceConnected] = useState(true); const [deviceConnected, setDeviceConnected] = useState(true);
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
const toggleNow = () => { const toggleNow = () => {
if (isNow) { if (isNow) {
@@ -81,9 +82,9 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
}, [firmware, date]); }, [firmware, date]);
useEffect(() => { useEffect(() => {
if (selectedDeviceId !== null && show) { if (deviceSerialNumber !== null && show) {
const asyncGet = async () => { const asyncGet = async () => {
const isConnected = await getDeviceConnection(selectedDeviceId); const isConnected = await getDeviceConnection(deviceSerialNumber, currentToken);
setDisableWaiting(!isConnected); setDisableWaiting(!isConnected);
setDeviceConnected(isConnected); setDeviceConnected(isConnected);
}; };
@@ -97,17 +98,17 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
setBlockFields(true); setBlockFields(true);
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
}; };
const parameters = { const parameters = {
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
when: isNow ? 0 : dateToUnix(date), when: isNow ? 0 : dateToUnix(date),
uri: firmware, uri: firmware,
}; };
axiosInstance axiosInstance
.post(`/device/${encodeURIComponent(selectedDeviceId)}/upgrade`, parameters, { headers }) .post(`/device/${encodeURIComponent(deviceSerialNumber)}/upgrade`, parameters, { headers })
.then(() => { .then(() => {
if (waitForUpgrade) { if (waitForUpgrade) {
setShowWaitingConsole(true); setShowWaitingConsole(true);
@@ -129,7 +130,7 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
<CModalTitle>{t('upgrade.title')}</CModalTitle> <CModalTitle>{t('upgrade.title')}</CModalTitle>
</CModalHeader> </CModalHeader>
<CModalBody> <CModalBody>
<UpgradeWaitingBody serialNumber={selectedDeviceId} /> <UpgradeWaitingBody serialNumber={deviceSerialNumber} />
</CModalBody> </CModalBody>
<CModalFooter> <CModalFooter>
<CButton color="secondary" onClick={toggleModal}> <CButton color="secondary" onClick={toggleModal}>

View File

@@ -10,23 +10,26 @@ import {
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import styles from './index.module.scss'; import styles from './index.module.scss';
const LatestStatisticsModal = ({ show, toggle, serialNumber }) => { const LatestStatisticsModal = ({ show, toggle }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [latestStats, setLatestStats] = useState(''); const [latestStats, setLatestStats] = useState('');
const getLatestStats = () => { const getLatestStats = () => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };
axiosInstance axiosInstance
.get(`/device/${serialNumber}/statistics?lastOnly=true`, options) .get(`/device/${deviceSerialNumber}/statistics?lastOnly=true`, options)
.then((response) => { .then((response) => {
setLatestStats(response.data); setLatestStats(response.data);
}) })
@@ -57,7 +60,6 @@ const LatestStatisticsModal = ({ show, toggle, serialNumber }) => {
}; };
LatestStatisticsModal.propTypes = { LatestStatisticsModal.propTypes = {
serialNumber: PropTypes.string.isRequired,
toggle: PropTypes.func.isRequired, toggle: PropTypes.func.isRequired,
show: PropTypes.bool.isRequired, show: PropTypes.bool.isRequired,
}; };

View File

@@ -1,15 +1,17 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import { v4 as createUuid } from 'uuid'; import { v4 as createUuid } from 'uuid';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import { unixToTime, capitalizeFirstLetter } from 'utils/helper'; import { unixToTime, capitalizeFirstLetter } from 'utils/helper';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import DeviceStatisticsChart from './DeviceStatisticsChart'; import DeviceStatisticsChart from './DeviceStatisticsChart';
const StatisticsChartList = ({ selectedDeviceId }) => { const StatisticsChartList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [statOptions, setStatOptions] = useState({ const [statOptions, setStatOptions] = useState({
interfaceList: [], interfaceList: [],
settings: {}, settings: {},
@@ -118,7 +120,7 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
params: { params: {
serialNumber: '24f5a207a130', serialNumber: '24f5a207a130',
@@ -126,7 +128,7 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
}; };
axiosInstance axiosInstance
.get(`/device/${selectedDeviceId}/statistics?newest=true&limit=50`, options) .get(`/device/${deviceSerialNumber}/statistics?newest=true&limit=50`, options)
.then((response) => { .then((response) => {
transformIntoDataset(response.data.data); transformIntoDataset(response.data.data);
}) })
@@ -134,10 +136,10 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
}; };
useEffect(() => { useEffect(() => {
if (selectedDeviceId) { if (deviceSerialNumber) {
getStatistics(); getStatistics();
} }
}, [selectedDeviceId]); }, [deviceSerialNumber]);
useEffect(() => { useEffect(() => {
eventBus.on('refreshInterfaceStatistics', () => getStatistics()); eventBus.on('refreshInterfaceStatistics', () => getStatistics());
@@ -173,8 +175,4 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
); );
}; };
StatisticsChartList.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default React.memo(StatisticsChartList); export default React.memo(StatisticsChartList);

View File

@@ -1,6 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import { import {
CDropdown, CDropdown,
CDropdownToggle, CDropdownToggle,
@@ -19,7 +18,7 @@ import StatisticsChartList from './StatisticsChartList';
import LatestStatisticsModal from './LatestStatisticsModal'; import LatestStatisticsModal from './LatestStatisticsModal';
import styles from './index.module.scss'; import styles from './index.module.scss';
const DeviceStatisticsCard = ({ selectedDeviceId }) => { const DeviceStatisticsCard = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const [showLatestModal, setShowLatestModal] = useState(false); const [showLatestModal, setShowLatestModal] = useState(false);
@@ -57,20 +56,12 @@ const DeviceStatisticsCard = ({ selectedDeviceId }) => {
</CRow> </CRow>
</CCardHeader> </CCardHeader>
<CCardBody className={styles.statsBody}> <CCardBody className={styles.statsBody}>
<StatisticsChartList selectedDeviceId={selectedDeviceId} /> <StatisticsChartList />
</CCardBody> </CCardBody>
</CCard> </CCard>
<LatestStatisticsModal <LatestStatisticsModal show={showLatestModal} toggle={toggleLatestModal} />
show={showLatestModal}
toggle={toggleLatestModal}
serialNumber={selectedDeviceId}
/>
</div> </div>
); );
}; };
DeviceStatisticsCard.propTypes = {
selectedDeviceId: PropTypes.string.isRequired,
};
export default DeviceStatisticsCard; export default DeviceStatisticsCard;

View File

@@ -13,10 +13,10 @@ import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import DatePicker from 'react-widgets/DatePicker'; import DatePicker from 'react-widgets/DatePicker';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { dateToUnix } from 'utils/helper'; import { dateToUnix } from 'utils/helper';
import 'react-widgets/styles.css'; import 'react-widgets/styles.css';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import LoadingButton from 'components/LoadingButton'; import LoadingButton from 'components/LoadingButton';
@@ -25,11 +25,12 @@ import styles from './index.module.scss';
const ActionModal = ({ show, toggleModal }) => { const ActionModal = ({ show, toggleModal }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [waiting, setWaiting] = useState(false); const [waiting, setWaiting] = useState(false);
const [result, setResult] = useState(null); const [result, setResult] = useState(null);
const [chosenDate, setChosenDate] = useState(new Date().toString()); const [chosenDate, setChosenDate] = useState(new Date().toString());
const [isNow, setIsNow] = useState(false); const [isNow, setIsNow] = useState(false);
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
const toggleNow = () => { const toggleNow = () => {
setIsNow(!isNow); setIsNow(!isNow);
@@ -52,21 +53,20 @@ const ActionModal = ({ show, toggleModal }) => {
const doAction = () => { const doAction = () => {
setWaiting(true); setWaiting(true);
const token = getToken();
const utcDate = new Date(chosenDate); const utcDate = new Date(chosenDate);
const parameters = { const parameters = {
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
when: isNow ? 0 : dateToUnix(utcDate), when: isNow ? 0 : dateToUnix(utcDate),
}; };
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance
.post(`/device/${encodeURIComponent(selectedDeviceId)}/reboot`, parameters, { headers }) .post(`/device/${encodeURIComponent(deviceSerialNumber)}/reboot`, parameters, { headers })
.then(() => { .then(() => {
setResult('success'); setResult('success');
}) })

View File

@@ -2,13 +2,14 @@ import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { CModalBody, CButton, CSpinner, CModalFooter } from '@coreui/react'; import { CModalBody, CButton, CSpinner, CModalFooter } from '@coreui/react';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import styles from './index.module.scss'; import styles from './index.module.scss';
const WaitingForTraceBody = ({ serialNumber, commandUuid, toggle }) => { const WaitingForTraceBody = ({ serialNumber, commandUuid, toggle }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const [secondsElapsed, setSecondsElapsed] = useState(0); const [secondsElapsed, setSecondsElapsed] = useState(0);
const [waitingForFile, setWaitingForFile] = useState(true); const [waitingForFile, setWaitingForFile] = useState(true);
@@ -16,7 +17,7 @@ const WaitingForTraceBody = ({ serialNumber, commandUuid, toggle }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
}; };
@@ -34,7 +35,7 @@ const WaitingForTraceBody = ({ serialNumber, commandUuid, toggle }) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/octet-stream', Accept: 'application/octet-stream',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${currentToken}`,
}, },
responseType: 'arraybuffer', responseType: 'arraybuffer',
}; };

View File

@@ -17,9 +17,9 @@ import {
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import 'react-widgets/styles.css'; import 'react-widgets/styles.css';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import getDeviceConnection from 'utils/deviceHelper'; import getDeviceConnection from 'utils/deviceHelper';
@@ -30,6 +30,8 @@ import styles from './index.module.scss';
const TraceModal = ({ show, toggleModal }) => { const TraceModal = ({ show, toggleModal }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [hadSuccess, setHadSuccess] = useState(false); const [hadSuccess, setHadSuccess] = useState(false);
const [hadFailure, setHadFailure] = useState(false); const [hadFailure, setHadFailure] = useState(false);
const [blockFields, setBlockFields] = useState(false); const [blockFields, setBlockFields] = useState(false);
@@ -43,8 +45,6 @@ const TraceModal = ({ show, toggleModal }) => {
const [waitingForTrace, setWaitingForTrace] = useState(false); const [waitingForTrace, setWaitingForTrace] = useState(false);
const [commandUuid, setCommandUuid] = useState(null); const [commandUuid, setCommandUuid] = useState(null);
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
const toggleWaitForTrace = () => { const toggleWaitForTrace = () => {
setWaitForTrace(!waitForTrace); setWaitForTrace(!waitForTrace);
}; };
@@ -65,10 +65,8 @@ const TraceModal = ({ show, toggleModal }) => {
setHadFailure(false); setHadFailure(false);
setHadSuccess(false); setHadSuccess(false);
const token = getToken();
const parameters = { const parameters = {
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
when: 0, when: 0,
network: chosenInterface, network: chosenInterface,
}; };
@@ -81,11 +79,11 @@ const TraceModal = ({ show, toggleModal }) => {
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance
.post(`/device/${encodeURIComponent(selectedDeviceId)}/trace`, parameters, { headers }) .post(`/device/${encodeURIComponent(deviceSerialNumber)}/trace`, parameters, { headers })
.then((response) => { .then((response) => {
setHadSuccess(true); setHadSuccess(true);
if (waitForTrace) { if (waitForTrace) {
@@ -105,9 +103,9 @@ const TraceModal = ({ show, toggleModal }) => {
}; };
useEffect(() => { useEffect(() => {
if (selectedDeviceId !== null && show) { if (deviceSerialNumber !== null && show) {
const asyncGet = async () => { const asyncGet = async () => {
const isConnected = await getDeviceConnection(selectedDeviceId); const isConnected = await getDeviceConnection(deviceSerialNumber, currentToken);
setIsDeviceConnected(isConnected); setIsDeviceConnected(isConnected);
}; };
asyncGet(); asyncGet();
@@ -119,7 +117,7 @@ const TraceModal = ({ show, toggleModal }) => {
return ( return (
<WaitingForTraceBody <WaitingForTraceBody
toggle={toggleModal} toggle={toggleModal}
serialNumber={selectedDeviceId} serialNumber={deviceSerialNumber}
commandUuid={commandUuid} commandUuid={commandUuid}
/> />
); );

View File

@@ -13,9 +13,9 @@ import {
} from '@coreui/react'; } from '@coreui/react';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { getToken } from 'utils/authHelper'; import { useAuth } from 'contexts/AuthProvider';
import { useDevice } from 'contexts/DeviceProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus'; import eventBus from 'utils/eventBus';
import LoadingButton from 'components/LoadingButton'; import LoadingButton from 'components/LoadingButton';
@@ -25,6 +25,8 @@ import styles from './index.module.scss';
const WifiScanModal = ({ show, toggleModal }) => { const WifiScanModal = ({ show, toggleModal }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentToken } = useAuth();
const { deviceSerialNumber } = useDevice();
const [hadSuccess, setHadSuccess] = useState(false); const [hadSuccess, setHadSuccess] = useState(false);
const [hadFailure, setHadFailure] = useState(false); const [hadFailure, setHadFailure] = useState(false);
const [waiting, setWaiting] = useState(false); const [waiting, setWaiting] = useState(false);
@@ -32,7 +34,6 @@ const WifiScanModal = ({ show, toggleModal }) => {
const [activeScan, setActiveScan] = useState(false); const [activeScan, setActiveScan] = useState(false);
const [hideOptions, setHideOptions] = useState(false); const [hideOptions, setHideOptions] = useState(false);
const [channelList, setChannelList] = useState([]); const [channelList, setChannelList] = useState([]);
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
const toggleVerbose = () => { const toggleVerbose = () => {
setVerbose(!choseVerbose); setVerbose(!choseVerbose);
@@ -88,20 +89,18 @@ const WifiScanModal = ({ show, toggleModal }) => {
setHadSuccess(false); setHadSuccess(false);
setWaiting(true); setWaiting(true);
const token = getToken();
const parameters = { const parameters = {
serialNumber: selectedDeviceId, serialNumber: deviceSerialNumber,
verbose: choseVerbose, verbose: choseVerbose,
activeScan, activeScan,
}; };
const headers = { const headers = {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${token}`, Authorization: `Bearer ${currentToken}`,
}; };
axiosInstance axiosInstance
.post(`/device/${encodeURIComponent(selectedDeviceId)}/wifiscan`, parameters, { headers }) .post(`/device/${encodeURIComponent(deviceSerialNumber)}/wifiscan`, parameters, { headers })
.then((response) => { .then((response) => {
const scanList = response?.data?.results?.status?.scan; const scanList = response?.data?.results?.status?.scan;

View File

@@ -0,0 +1,21 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
const AuthContext = React.createContext();
export const AuthProvider = ({ token, children }) => {
const [currentToken, setCurrentToken] = useState(token);
return (
<AuthContext.Provider value={{ currentToken, setCurrentToken }}>
{children}
</AuthContext.Provider>
);
};
AuthProvider.propTypes = {
token: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
};
export const useAuth = () => React.useContext(AuthContext);

View File

@@ -0,0 +1,21 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
const DeviceContext = React.createContext();
export const DeviceProvider = ({ serialNumber, children }) => {
const [deviceSerialNumber, setDeviceSerialNumber] = useState(serialNumber);
return (
<DeviceContext.Provider value={{ deviceSerialNumber, setDeviceSerialNumber }}>
{children}
</DeviceContext.Provider>
);
};
DeviceProvider.propTypes = {
serialNumber: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
};
export const useDevice = () => React.useContext(DeviceContext);

View File

@@ -1,9 +1,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import 'index.css'; import 'index.css';
import { Provider } from 'react-redux';
import App from 'App'; import App from 'App';
import store from 'store';
import { icons } from 'assets/icons'; import { icons } from 'assets/icons';
import 'i18n'; import 'i18n';
@@ -11,9 +9,7 @@ React.icons = icons;
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<Provider store={store}> <App />
<App />
</Provider>
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root'), document.getElementById('root'),
); );

View File

@@ -1,5 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
CHeader, CHeader,
@@ -11,26 +10,25 @@ import {
CLink, CLink,
CPopover, CPopover,
} from '@coreui/react'; } from '@coreui/react';
import PropTypes from 'prop-types';
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import { cilAccountLogout } from '@coreui/icons'; import { cilAccountLogout } from '@coreui/icons';
import { logout } from 'utils/authHelper'; import { logout } from 'utils/authHelper';
import routes from 'routes'; import routes from 'routes';
import LanguageSwitcher from 'components/LanguageSwitcher'; import LanguageSwitcher from 'components/LanguageSwitcher';
const TheHeader = () => { const TheHeader = ({ showSidebar, setShowSidebar }) => {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const dispatch = useDispatch();
const [translatedRoutes, setTranslatedRoutes] = useState(routes); const [translatedRoutes, setTranslatedRoutes] = useState(routes);
const sidebarShow = useSelector((state) => state.sidebarShow);
const toggleSidebar = () => { const toggleSidebar = () => {
const val = [true, 'responsive'].includes(sidebarShow) ? false : 'responsive'; const val = [true, 'responsive'].includes(showSidebar) ? false : 'responsive';
dispatch({ type: 'set', sidebarShow: val }); setShowSidebar(val);
}; };
const toggleSidebarMobile = () => { const toggleSidebarMobile = () => {
const val = [false, 'responsive'].includes(sidebarShow) ? true : 'responsive'; const val = [false, 'responsive'].includes(showSidebar) ? true : 'responsive';
dispatch({ type: 'set', sidebarShow: val }); setShowSidebar(val);
}; };
useEffect(() => { useEffect(() => {
@@ -69,4 +67,9 @@ const TheHeader = () => {
); );
}; };
TheHeader.propTypes = {
showSidebar: PropTypes.string.isRequired,
setShowSidebar: PropTypes.func.isRequired,
};
export default TheHeader; export default TheHeader;

View File

@@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { import {
CCreateElement, CCreateElement,
CSidebar, CSidebar,
@@ -11,14 +10,13 @@ import {
CSidebarNavDropdown, CSidebarNavDropdown,
CSidebarNavItem, CSidebarNavItem,
} from '@coreui/react'; } from '@coreui/react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import logoBar from 'assets/OpenWiFi_LogoLockup_WhiteColour.svg'; import logoBar from 'assets/OpenWiFi_LogoLockup_WhiteColour.svg';
import styles from './index.module.scss'; import styles from './index.module.scss';
const TheSidebar = () => { const TheSidebar = ({ showSidebar, setShowSidebar }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useDispatch();
const show = useSelector((state) => state.sidebarShow);
const navigation = [ const navigation = [
{ {
@@ -30,7 +28,7 @@ const TheSidebar = () => {
]; ];
return ( return (
<CSidebar show={show} onShowChange={(val) => dispatch({ type: 'set', sidebarShow: val })}> <CSidebar show={showSidebar} onShowChange={(val) => setShowSidebar(val)}>
<CSidebarBrand className="d-md-down-none" to="/devices"> <CSidebarBrand className="d-md-down-none" to="/devices">
<img <img
className={[styles.sidebarImgFull, 'c-sidebar-brand-full'].join(' ')} className={[styles.sidebarImgFull, 'c-sidebar-brand-full'].join(' ')}
@@ -59,4 +57,9 @@ const TheSidebar = () => {
); );
}; };
TheSidebar.propTypes = {
showSidebar: PropTypes.string.isRequired,
setShowSidebar: PropTypes.func.isRequired,
};
export default React.memo(TheSidebar); export default React.memo(TheSidebar);

View File

@@ -1,21 +1,17 @@
import React from 'react'; import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import TheContent from './Content'; import TheContent from './Content';
import TheSidebar from './Sidebar'; import TheSidebar from './Sidebar';
import TheFooter from './Footer'; import TheFooter from './Footer';
import TheHeader from './Header'; import TheHeader from './Header';
const TheLayout = (props) => { const TheLayout = () => {
const { isLoggedIn } = useSelector((state) => state.connected); const [showSidebar, setShowSidebar] = useState('responsive');
if (isLoggedIn) {
return <div>{props.children}</div>;
}
return ( return (
<div className="c-app c-default-layout"> <div className="c-app c-default-layout">
<TheSidebar /> <TheSidebar showSidebar={showSidebar} setShowSidebar={setShowSidebar} />
<div className="c-wrapper"> <div className="c-wrapper">
<TheHeader /> <TheHeader showSidebar={showSidebar} setShowSidebar={setShowSidebar} />
<div className="c-body"> <div className="c-body">
<TheContent /> <TheContent />
</div> </div>
@@ -25,12 +21,4 @@ const TheLayout = (props) => {
); );
}; };
TheLayout.propTypes = {
children: PropTypes.instanceOf(Object),
};
TheLayout.defaultProps = {
children: {},
};
export default TheLayout; export default TheLayout;

View File

@@ -1,5 +1,4 @@
import React, { useEffect } from 'react'; import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { CRow, CCol } from '@coreui/react'; import { CRow, CCol } from '@coreui/react';
import DeviceHealth from 'components/DeviceHealth'; import DeviceHealth from 'components/DeviceHealth';
@@ -9,40 +8,33 @@ import DeviceLogs from 'components/DeviceLogs';
import DeviceStatisticsCard from 'components/InterfaceStatistics'; import DeviceStatisticsCard from 'components/InterfaceStatistics';
import DeviceActionCard from 'components/DeviceActionCard'; import DeviceActionCard from 'components/DeviceActionCard';
import DeviceStatusCard from 'components/DeviceStatusCard'; import DeviceStatusCard from 'components/DeviceStatusCard';
import { DeviceProvider } from 'contexts/DeviceProvider';
const DevicePage = () => { const DevicePage = () => {
const dispatch = useDispatch();
const { deviceId } = useParams(); const { deviceId } = useParams();
const previouslySelectedDeviceId = useSelector((state) => state.selectedDeviceId);
useEffect(() => {
if (deviceId && deviceId !== previouslySelectedDeviceId)
dispatch({ type: 'set', selectedDeviceId: deviceId });
}, [deviceId]);
return ( return (
<> <div className="App">
<div className="App"> <DeviceProvider serialNumber={deviceId}>
<CRow> <CRow>
<CCol xs="12" sm="6"> <CCol xs="12" sm="6">
<DeviceStatusCard selectedDeviceId={deviceId} /> <DeviceStatusCard />
<DeviceConfiguration selectedDeviceId={deviceId} /> <DeviceConfiguration />
</CCol> </CCol>
<CCol xs="12" sm="6"> <CCol xs="12" sm="6">
<DeviceLogs selectedDeviceId={deviceId} /> <DeviceLogs />
<DeviceHealth selectedDeviceId={deviceId} /> <DeviceHealth />
<DeviceActionCard selectedDeviceId={deviceId} /> <DeviceActionCard />
</CCol> </CCol>
</CRow> </CRow>
<CRow> <CRow>
<CCol> <CCol>
<DeviceStatisticsCard selectedDeviceId={deviceId} /> <DeviceStatisticsCard />
<CommandHistory selectedDeviceId={deviceId} /> <CommandHistory />
</CCol> </CCol>
</CRow> </CRow>
</div> </DeviceProvider>
</> </div>
); );
}; };

View File

@@ -18,8 +18,8 @@ import {
CInvalidFeedback, CInvalidFeedback,
} from '@coreui/react'; } from '@coreui/react';
import CIcon from '@coreui/icons-react'; import CIcon from '@coreui/icons-react';
import { useAuth } from 'contexts/AuthProvider';
import { cilUser, cilLockLocked, cilLink } from '@coreui/icons'; import { cilUser, cilLockLocked, cilLink } from '@coreui/icons';
import { useDispatch } from 'react-redux';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import logo from 'assets/OpenWiFi_LogoLockup_DarkGreyColour.svg'; import logo from 'assets/OpenWiFi_LogoLockup_DarkGreyColour.svg';
import LanguageSwitcher from 'components/LanguageSwitcher'; import LanguageSwitcher from 'components/LanguageSwitcher';
@@ -27,7 +27,7 @@ import styles from './index.module.scss';
const Login = () => { const Login = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useDispatch(); const { setCurrentToken } = useAuth();
const [userId, setUsername] = useState(''); const [userId, setUsername] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
const [gatewayUrl, setGatewayUrl] = useState(''); const [gatewayUrl, setGatewayUrl] = useState('');
@@ -87,7 +87,7 @@ const Login = () => {
.then((response) => { .then((response) => {
sessionStorage.setItem('gw_url', `${gatewayUrlToUse}/api/v1`); sessionStorage.setItem('gw_url', `${gatewayUrlToUse}/api/v1`);
sessionStorage.setItem('access_token', response.data.access_token); sessionStorage.setItem('access_token', response.data.access_token);
dispatch({ type: 'set', connected: true }); setCurrentToken(response.data.access_token);
}) })
.catch(() => { .catch(() => {
setHadError(true); setHadError(true);

20
src/router/index.js Normal file
View File

@@ -0,0 +1,20 @@
import { useAuth } from 'contexts/AuthProvider';
import { Route } from 'react-router-dom';
import React from 'react';
const TheLayout = React.lazy(() => import('layout'));
const Login = React.lazy(() => import('pages/LoginPage'));
const Routes = () => {
const { currentToken } = useAuth();
return (
<Route
path="/"
name="Devices"
render={(props) => (currentToken !== '' ? <TheLayout {...props} /> : <Login {...props} />)}
/>
);
};
export default Routes;

View File

@@ -3,9 +3,7 @@ import React from 'react';
const DevicePage = React.lazy(() => import('pages/DevicePage')); const DevicePage = React.lazy(() => import('pages/DevicePage'));
const DeviceListPage = React.lazy(() => import('pages/DeviceListPage')); const DeviceListPage = React.lazy(() => import('pages/DeviceListPage'));
const routes = [ export default [
{ path: '/devices', exact: true, name: 'common.devices', component: DeviceListPage }, { path: '/devices', exact: true, name: 'common.devices', component: DeviceListPage },
{ path: '/devices/:deviceId', name: 'common.device_page', component: DevicePage }, { path: '/devices/:deviceId', name: 'common.device_page', component: DevicePage },
]; ];
export default routes;

View File

@@ -1,19 +0,0 @@
import { createStore } from 'redux';
const initialState = {
sidebarShow: 'responsive',
connected: false,
selectedDeviceId: null,
};
const changeState = (state = initialState, { type, ...rest }) => {
switch (type) {
case 'set':
return { ...state, ...rest };
default:
return state;
}
};
const store = createStore(changeState);
export default store;

View File

@@ -1,11 +1,10 @@
import { getToken } from 'utils/authHelper';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
export default async (deviceId) => { export default async (deviceId, token) => {
const options = { const options = {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
Authorization: `Bearer ${getToken()}`, Authorization: `Bearer ${token}`,
}, },
}; };