mirror of
https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
synced 2025-11-01 18:57:46 +00:00
Waiting for trace
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"commands": {
|
||||
"error": "Fehler beim Senden des Befehls!",
|
||||
"success": "Befehl erfolgreich übermittelt",
|
||||
"success": "Der Befehl wurde erfolgreich gesendet. Sie können das Ergebnis im Befehlsprotokoll anzeigen",
|
||||
"title": "Gerätebefehle"
|
||||
},
|
||||
"common": {
|
||||
@@ -160,8 +160,10 @@
|
||||
"trace": {
|
||||
"choose_network": "Netzwerk auswählen",
|
||||
"directions": "Starten Sie eine Fernverfolgung dieses Geräts für eine bestimmte Dauer oder eine Anzahl von Paketen",
|
||||
"download_trace": "Klicke hier zum herunterladen",
|
||||
"packets": "Pakete",
|
||||
"title": "Trace-Gerät"
|
||||
"title": "Trace-Gerät",
|
||||
"waiting_seconds": "Verstrichene Zeit: {{seconds}} Sekunden"
|
||||
},
|
||||
"upgrade": {
|
||||
"command_submitted": "Befehl gesendet",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"commands": {
|
||||
"error": "Error while submitting command!",
|
||||
"success": "Command submitted successfully",
|
||||
"success": "Command submitted successfully, you can look at the Commands log for the result",
|
||||
"title": "Device Commands"
|
||||
},
|
||||
"common": {
|
||||
@@ -160,8 +160,10 @@
|
||||
"trace": {
|
||||
"choose_network": "Choose network",
|
||||
"directions": "Launch a remote trace of this device for either a specific duration or a number of packets",
|
||||
"download_trace": "Click here to download",
|
||||
"packets": "Packets",
|
||||
"title": "Trace Device"
|
||||
"title": "Trace Device",
|
||||
"waiting_seconds": "Time Elapsed: {{seconds}} seconds"
|
||||
},
|
||||
"upgrade": {
|
||||
"command_submitted": "Command submitted",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"commands": {
|
||||
"error": "¡Error al enviar el comando!",
|
||||
"success": "Comando enviado con éxito",
|
||||
"success": "Comando enviado con éxito, puede consultar el registro de Comandos para ver el resultado",
|
||||
"title": "Comandos del dispositivo"
|
||||
},
|
||||
"common": {
|
||||
@@ -160,8 +160,10 @@
|
||||
"trace": {
|
||||
"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",
|
||||
"download_trace": "Haga click aquí para descargar",
|
||||
"packets": "Paquetes",
|
||||
"title": "Dispositivo de seguimiento"
|
||||
"title": "Dispositivo de seguimiento",
|
||||
"waiting_seconds": "Tiempo transcurrido: {{seconds}} segundos"
|
||||
},
|
||||
"upgrade": {
|
||||
"command_submitted": "Comando enviado",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"commands": {
|
||||
"error": "Erreur lors de la soumission de la commande !",
|
||||
"success": "Commande soumise avec succès",
|
||||
"success": "Commande soumise avec succès, vous pouvez consulter le journal des commandes pour le résultat",
|
||||
"title": "Commandes de l'appareil"
|
||||
},
|
||||
"common": {
|
||||
@@ -160,8 +160,10 @@
|
||||
"trace": {
|
||||
"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",
|
||||
"download_trace": "Cliquez ici pour télécharger",
|
||||
"packets": "Paquets",
|
||||
"title": "Dispositif de traçage"
|
||||
"title": "Dispositif de traçage",
|
||||
"waiting_seconds": "Temps écoulé : {{seconds}} secondes"
|
||||
},
|
||||
"upgrade": {
|
||||
"command_submitted": "Commande soumise",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"commands": {
|
||||
"error": "Erro ao enviar comando!",
|
||||
"success": "Comando enviado com sucesso",
|
||||
"success": "Comando enviado com sucesso, você pode consultar o log de Comandos para ver o resultado",
|
||||
"title": "Comandos de dispositivo"
|
||||
},
|
||||
"common": {
|
||||
@@ -160,8 +160,10 @@
|
||||
"trace": {
|
||||
"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",
|
||||
"download_trace": "Clique aqui para baixar",
|
||||
"packets": "Pacotes",
|
||||
"title": "Dispositivo de rastreamento"
|
||||
"title": "Dispositivo de rastreamento",
|
||||
"waiting_seconds": "Tempo decorrido: {{seconds}} segundos"
|
||||
},
|
||||
"upgrade": {
|
||||
"command_submitted": "Comando enviado",
|
||||
|
||||
@@ -24,7 +24,7 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
.get(`/device/${encodeURIComponent(serialNumber)}/status`, options)
|
||||
.then((response) => response.data.connected)
|
||||
.catch(() => {});
|
||||
}
|
||||
};
|
||||
|
||||
const getFirmwareVersion = () => {
|
||||
const options = {
|
||||
@@ -38,28 +38,27 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
.get(`/device/${encodeURIComponent(serialNumber)}`, options)
|
||||
.then((response) => response.data.firmware)
|
||||
.catch(() => {});
|
||||
}
|
||||
};
|
||||
|
||||
const refreshStep = () => {
|
||||
if(currentStep === 0 && !getDeviceConnection){
|
||||
if (currentStep === 0 && !getDeviceConnection) {
|
||||
const labelsToAdd = [
|
||||
t('upgrade.device_disconnected'),
|
||||
t('upgrade.device_upgrading_firmware'),
|
||||
t('upgrade.waiting_for_device'),
|
||||
];
|
||||
setLabelsToShow([...labelsToShow, ...labelsToAdd])
|
||||
setLabelsToShow([...labelsToShow, ...labelsToAdd]);
|
||||
setCurrentStep(1);
|
||||
}
|
||||
else if(currentStep === 1 && getDeviceConnection()){
|
||||
} else if (currentStep === 1 && getDeviceConnection()) {
|
||||
const newFirmware = `: ${getFirmwareVersion()}`;
|
||||
const labelsToAdd = [
|
||||
t('upgrade.device_reconnected'),
|
||||
`${t('upgrade.new_version')}: ${newFirmware}`
|
||||
`${t('upgrade.new_version')}: ${newFirmware}`,
|
||||
];
|
||||
setLabelsToShow([...labelsToShow, ...labelsToAdd]);
|
||||
setCurrentStep(2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const refreshIntervalId = setInterval(() => {
|
||||
@@ -68,7 +67,7 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
|
||||
const timerIntervalId = setInterval(() => {
|
||||
setSecondsElapsed(secondsElapsed + 1);
|
||||
})
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearInterval(refreshIntervalId);
|
||||
@@ -79,10 +78,14 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
return (
|
||||
<CModalBody>
|
||||
<div className="consoleBox">
|
||||
{
|
||||
labelsToShow.map((label) => <p key={createUuid()}>{new Date().toString()}: {label}</p>)
|
||||
}
|
||||
<p>{t('common.seconds_elapsed')}: {secondsElapsed}</p>
|
||||
{labelsToShow.map((label) => (
|
||||
<p key={createUuid()}>
|
||||
{new Date().toString()}: {label}
|
||||
</p>
|
||||
))}
|
||||
<p>
|
||||
{t('common.seconds_elapsed')}: {secondsElapsed}
|
||||
</p>
|
||||
</div>
|
||||
</CModalBody>
|
||||
);
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
CRow,
|
||||
CInput,
|
||||
CInvalidFeedback,
|
||||
CModalFooter
|
||||
CModalFooter,
|
||||
} from '@coreui/react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -21,9 +21,10 @@ import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import ButtonFooter from './containers/UpgradeFooter';
|
||||
import getDeviceConnection from 'utils/deviceHelper';
|
||||
import ButtonFooter from './UpgradeFooter';
|
||||
import styles from './index.module.scss';
|
||||
import UpgradeWaitingBody from './containers/UpgradeWaitingBody';
|
||||
import UpgradeWaitingBody from './UpgradeWaitingBody';
|
||||
|
||||
const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -37,10 +38,18 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
const [disabledWaiting, setDisableWaiting] = useState(false);
|
||||
const [waitingForUpgrade, setWaitingForUpgrade] = useState(false);
|
||||
const [showWaitingConsole, setShowWaitingConsole] = useState(false);
|
||||
const [lastResult, setLastResult] = useState(null);
|
||||
const [deviceConnected, setDeviceConnected] = useState(true);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleNow = () => {
|
||||
if(isNow){
|
||||
setWaitForUpgrade(false);
|
||||
setDisableWaiting(true);
|
||||
}
|
||||
else{
|
||||
setDisableWaiting(false);
|
||||
}
|
||||
|
||||
setIsNow(!isNow);
|
||||
};
|
||||
|
||||
@@ -48,20 +57,6 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
setWaitForUpgrade(waitForUpgrade);
|
||||
};
|
||||
|
||||
const getDeviceConnection = async () => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
};
|
||||
|
||||
return axiosInstance
|
||||
.get(`/device/${encodeURIComponent(selectedDeviceId)}/status`, options)
|
||||
.then((response) => response.data.connected)
|
||||
.catch(() => false);
|
||||
}
|
||||
|
||||
const formValidation = () => {
|
||||
let valid = true;
|
||||
if (firmware.trim() === '') {
|
||||
@@ -87,11 +82,12 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
}, [firmware, date]);
|
||||
|
||||
useEffect(() => {
|
||||
if(selectedDeviceId !== null && show){
|
||||
if (selectedDeviceId !== null && show) {
|
||||
const asyncGet = async () => {
|
||||
const isConnected = await getDeviceConnection();
|
||||
const isConnected = await getDeviceConnection(selectedDeviceId);
|
||||
setDisableWaiting(!isConnected);
|
||||
}
|
||||
setDeviceConnected(isConnected);
|
||||
};
|
||||
asyncGet();
|
||||
}
|
||||
}, [show]);
|
||||
@@ -112,18 +108,16 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
uri: firmware,
|
||||
};
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/upgrade`, parameters, { headers })
|
||||
.then((response) => {
|
||||
setLastResult(response);
|
||||
if(waitForUpgrade) {
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/reboot`, parameters, { headers })
|
||||
.then(() => {
|
||||
if (waitForUpgrade) {
|
||||
console.log('waiting');
|
||||
setShowWaitingConsole(true);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setLastResult('error');
|
||||
})
|
||||
.finally(() => {
|
||||
console.log(lastResult);
|
||||
setBlockFields(false);
|
||||
setWaitingForUpgrade(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
@@ -131,16 +125,14 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
}
|
||||
};
|
||||
|
||||
if(showWaitingConsole){
|
||||
if (showWaitingConsole) {
|
||||
return (
|
||||
<CModal show={show} onClose={toggleModal}>
|
||||
<CModalHeader closeButton>
|
||||
<CModalTitle>{t('upgrade.title')}</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CModalBody>
|
||||
<UpgradeWaitingBody
|
||||
serialNumber={selectedDeviceId}
|
||||
/>
|
||||
<UpgradeWaitingBody serialNumber={selectedDeviceId} />
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
@@ -158,37 +150,6 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
</CModalHeader>
|
||||
<CModalBody>
|
||||
<h6>{t('upgrade.directions')}</h6>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>{t('common.execute_now')}</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
disabled={blockFields}
|
||||
color="primary"
|
||||
defaultChecked={isNow}
|
||||
onClick={toggleNow}
|
||||
labelOn={t('common.yes')}
|
||||
labelOff={t('common.no')}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow hidden={isNow}>
|
||||
<CCol md="4" className={styles.spacedColumn}>
|
||||
<p>{t('upgrade.time')}</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
selected={new Date(date)}
|
||||
value={new Date(date)}
|
||||
className={('form-control', { 'is-invalid': !validDate })}
|
||||
includeTime
|
||||
disabled={blockFields}
|
||||
onChange={(newDate) => setDate(newDate.toString())}
|
||||
/>
|
||||
<CInvalidFeedback>{t('common.need_date')}</CInvalidFeedback>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="4" className={styles.spacedColumn}>
|
||||
<p>{t('upgrade.firmware_uri')}</p>
|
||||
@@ -209,7 +170,41 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>{t('upgrade.wait_for_upgrade')}<b hidden={!disabledWaiting}> {t('upgrade.offline_device')}</b></p>
|
||||
<p className={styles.spacedText}>{t('common.execute_now')}</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
disabled={blockFields}
|
||||
color="primary"
|
||||
defaultChecked={isNow}
|
||||
onClick={toggleNow}
|
||||
labelOn={t('common.yes')}
|
||||
labelOff={t('common.no')}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow} hidden={isNow}>
|
||||
<CCol md="4" className={styles.spacedColumn}>
|
||||
<p>{t('upgrade.time')}</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
selected={new Date(date)}
|
||||
value={new Date(date)}
|
||||
className={('form-control', { 'is-invalid': !validDate })}
|
||||
includeTime
|
||||
disabled={blockFields}
|
||||
onChange={(newDate) => setDate(newDate.toString())}
|
||||
/>
|
||||
<CInvalidFeedback>{t('common.need_date')}</CInvalidFeedback>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow} hidden={!isNow || disabledWaiting || !deviceConnected}>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>
|
||||
{t('upgrade.wait_for_upgrade')}
|
||||
<b hidden={!disabledWaiting}> {t('upgrade.offline_device')}</b>
|
||||
</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
CButton,
|
||||
CModal,
|
||||
@@ -30,11 +30,11 @@ const LatestStatisticsModal = ({ show, toggle, serialNumber }) => {
|
||||
.then((response) => {
|
||||
setLatestStats(response.data);
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if(show){
|
||||
if (show) {
|
||||
getLatestStats();
|
||||
}
|
||||
}, [show]);
|
||||
@@ -54,7 +54,7 @@ const LatestStatisticsModal = ({ show, toggle, serialNumber }) => {
|
||||
</CModalFooter>
|
||||
</CModal>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
LatestStatisticsModal.propTypes = {
|
||||
serialNumber: PropTypes.string.isRequired,
|
||||
|
||||
@@ -60,14 +60,15 @@ const StatisticsChartList = ({ selectedDeviceId, lastRefresh }) => {
|
||||
// Looping through the interfaces of the log
|
||||
for (const inter of log.data.interfaces) {
|
||||
interfaceList[interfaceTypes[inter.name]][0].data.push(
|
||||
Math.floor(inter.counters.tx_bytes / 1024),
|
||||
inter.counters?.tx_bytes? Math.floor(inter.counters.tx_bytes / 1024) : 0
|
||||
);
|
||||
interfaceList[interfaceTypes[inter.name]][1].data.push(
|
||||
Math.floor(inter.counters.rx_bytes / 1024),
|
||||
inter.counters?.rx_bytes? Math.floor(inter.counters.rx_bytes / 1024) : 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const options = {
|
||||
chart: {
|
||||
id: 'chart',
|
||||
@@ -105,7 +106,6 @@ const StatisticsChartList = ({ selectedDeviceId, lastRefresh }) => {
|
||||
interfaceList,
|
||||
settings: options,
|
||||
};
|
||||
|
||||
if (statOptions !== newOptions) {
|
||||
setStatOptions(newOptions);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CDropdown, CDropdownToggle, CDropdownMenu, CDropdownItem, CCard, CCardHeader, CCardBody, CRow, CCol } from '@coreui/react';
|
||||
import {
|
||||
CDropdown,
|
||||
CDropdownToggle,
|
||||
CDropdownMenu,
|
||||
CDropdownItem,
|
||||
CCard,
|
||||
CCardHeader,
|
||||
CCardBody,
|
||||
CRow,
|
||||
CCol,
|
||||
} from '@coreui/react';
|
||||
import { cilOptions } from '@coreui/icons';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import StatisticsChartList from './StatisticsChartList';
|
||||
@@ -15,7 +25,7 @@ const DeviceStatisticsCard = ({ selectedDeviceId }) => {
|
||||
|
||||
const toggleLatestModal = () => {
|
||||
setShowLatestModal(!showLatestModal);
|
||||
}
|
||||
};
|
||||
|
||||
const refresh = () => {
|
||||
setLastRefresh(new Date().toString());
|
||||
@@ -26,20 +36,19 @@ const DeviceStatisticsCard = ({ selectedDeviceId }) => {
|
||||
<CCard>
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol><h4>{t('statistics.title')}</h4></CCol>
|
||||
<CCol>
|
||||
<h4>{t('statistics.title')}</h4>
|
||||
</CCol>
|
||||
<CCol className={styles.alignRight}>
|
||||
<CDropdown className="m-1 btn-group">
|
||||
<CDropdownToggle>
|
||||
<CIcon
|
||||
name="cil-options"
|
||||
content={cilOptions}
|
||||
size="lg"
|
||||
color="primary"
|
||||
/>
|
||||
<CIcon name="cil-options" content={cilOptions} size="lg" color="primary" />
|
||||
</CDropdownToggle>
|
||||
<CDropdownMenu>
|
||||
<CDropdownItem onClick={refresh}>{t('common.refresh')}</CDropdownItem>
|
||||
<CDropdownItem onClick={toggleLatestModal}>{t('statistics.show_latest')}</CDropdownItem>
|
||||
<CDropdownItem onClick={toggleLatestModal}>
|
||||
{t('statistics.show_latest')}
|
||||
</CDropdownItem>
|
||||
</CDropdownMenu>
|
||||
</CDropdown>
|
||||
</CCol>
|
||||
@@ -49,7 +58,11 @@ const DeviceStatisticsCard = ({ selectedDeviceId }) => {
|
||||
<StatisticsChartList selectedDeviceId={selectedDeviceId} lastRefresh={lastRefresh} />
|
||||
</CCardBody>
|
||||
</CCard>
|
||||
<LatestStatisticsModal show={showLatestModal} toggle={toggleLatestModal} serialNumber={selectedDeviceId}/>
|
||||
<LatestStatisticsModal
|
||||
show={showLatestModal}
|
||||
toggle={toggleLatestModal}
|
||||
serialNumber={selectedDeviceId}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
101
src/components/TraceModal/WaitingForTraceBody.js
Normal file
101
src/components/TraceModal/WaitingForTraceBody.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CModalBody, CButton, CSpinner } from '@coreui/react';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const WaitingForTraceBody = ({serialNumber, commandUuid}) => {
|
||||
const { t } = useTranslation();
|
||||
const [secondsElapsed, setSecondsElapsed] = useState(0);
|
||||
const [waitingForFile, setWaitingForFile] = useState(true);
|
||||
|
||||
const getTraceResult = () => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/command/${encodeURIComponent(commandUuid)}`, options)
|
||||
.then((response) => {
|
||||
if(response.data.waitingForFile === 0){
|
||||
setWaitingForFile(false);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
const downloadTrace = () => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/octet-stream',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
responseType: 'arraybuffer',
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/file/${commandUuid}?serialNumber=${serialNumber}`, options)
|
||||
.then((response) => {
|
||||
const blob = new Blob([response.data], { type: 'application/octet-stream' });
|
||||
const link = document.createElement('a');
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = `Trace_${commandUuid}.pcap`;
|
||||
link.click();
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setSecondsElapsed(secondsElapsed + 1);
|
||||
}, 1000);
|
||||
if(!waitingForFile){
|
||||
clearInterval(timer);
|
||||
}
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
}
|
||||
}, [waitingForFile, secondsElapsed]);
|
||||
|
||||
useEffect(() => {
|
||||
const refreshStatus = setInterval(() => {
|
||||
getTraceResult();
|
||||
}, 5000);
|
||||
if(!waitingForFile){
|
||||
clearInterval(refreshStatus);
|
||||
}
|
||||
return () => {
|
||||
clearInterval(refreshStatus);
|
||||
}
|
||||
}, [waitingForFile]);
|
||||
|
||||
return (
|
||||
<CModalBody>
|
||||
<p>{t('trace.waiting_seconds', {seconds: secondsElapsed})}</p>
|
||||
<div className={styles.centerDiv}>
|
||||
<CSpinner hidden={!waitingForFile} />
|
||||
</div>
|
||||
<CButton
|
||||
hidden={waitingForFile}
|
||||
onClick={downloadTrace}
|
||||
disabled={waitingForFile}
|
||||
color="link"
|
||||
block
|
||||
>
|
||||
{t('trace.download_trace')}
|
||||
</CButton>
|
||||
</CModalBody>
|
||||
);
|
||||
}
|
||||
|
||||
WaitingForTraceBody.propTypes = {
|
||||
serialNumber: PropTypes.string.isRequired,
|
||||
commandUuid: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default WaitingForTraceBody;
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
CRow,
|
||||
CInvalidFeedback,
|
||||
CSelect,
|
||||
CSwitch,
|
||||
CForm,
|
||||
CInputRadio,
|
||||
CFormGroup,
|
||||
@@ -19,28 +20,44 @@ import { useTranslation } from 'react-i18next';
|
||||
import DatePicker from 'react-widgets/DatePicker';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { convertDateToUtc, dateToUnix } from 'utils/helper';
|
||||
import { dateToUnix } from 'utils/helper';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import getDeviceConnection from 'utils/deviceHelper';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
|
||||
import WaitingForTraceBody from './WaitingForTraceBody';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const TraceModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
const [hadFailure, setHadFailure] = useState(false);
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
const [blockFields, setBlockFields] = useState(false);
|
||||
const [usingDuration, setUsingDuration] = useState(true);
|
||||
const [duration, setDuration] = useState(20);
|
||||
const [packets, setPackets] = useState(100);
|
||||
const [chosenDate, setChosenDate] = useState(new Date().toString());
|
||||
const [responseBody, setResponseBody] = useState('');
|
||||
const [chosenInterface, setChosenInterface] = useState('up');
|
||||
const [isDeviceConnected, setIsDeviceConnected] = useState(false);
|
||||
const [isNow, setIsNow] = useState(true);
|
||||
const [waitForTrace, setWaitForTrace] = useState(false);
|
||||
const [waitingForTrace, setWaitingForTrace] = useState(false);
|
||||
const [commandUuid, setCommandUuid] = useState(null);
|
||||
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleWaitForTrace = () => {
|
||||
setWaitForTrace(!waitForTrace);
|
||||
}
|
||||
|
||||
const toggleNow = () => {
|
||||
setIsNow(!isNow);
|
||||
}
|
||||
|
||||
const setDate = (date) => {
|
||||
if (date) {
|
||||
setChosenDate(date.toString());
|
||||
@@ -48,35 +65,27 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setWaitForTrace(false);
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setChosenDate(new Date().toString());
|
||||
setResponseBody('');
|
||||
setDuration(20);
|
||||
setPackets(100);
|
||||
setChosenInterface('up');
|
||||
setWaitingForTrace(false);
|
||||
}, [show]);
|
||||
|
||||
const doAction = () => {
|
||||
setBlockFields(true);
|
||||
setHadFailure(false);
|
||||
setHadSuccess(false);
|
||||
setWaiting(true);
|
||||
|
||||
const token = getToken();
|
||||
const dateChosen = new Date(chosenDate);
|
||||
const now = new Date();
|
||||
let utcDateString = dateChosen.toISOString();
|
||||
|
||||
if (dateChosen <= now) {
|
||||
const newDate = new Date();
|
||||
newDate.setSeconds(newDate.getSeconds() + 60);
|
||||
utcDateString = newDate.toISOString();
|
||||
}
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
when: dateChosen <= now ? 0 : dateToUnix(utcDateString),
|
||||
when: isNow ? 0 : dateToUnix(new Date(chosenDate)),
|
||||
network: chosenInterface,
|
||||
};
|
||||
|
||||
@@ -93,158 +102,218 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/trace`, parameters, { headers })
|
||||
.then(() => {
|
||||
.then((response) => {
|
||||
setHadSuccess(true);
|
||||
if(waitForTrace) {
|
||||
setCommandUuid(response.data.UUID);
|
||||
setWaitingForTrace(true);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setResponseBody(t('commands.error'));
|
||||
setHadFailure(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setWaiting(false);
|
||||
setBlockFields(false);
|
||||
setBlockFields(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId !== null && show) {
|
||||
const asyncGet = async () => {
|
||||
const isConnected = await getDeviceConnection(selectedDeviceId);
|
||||
setIsDeviceConnected(isConnected);
|
||||
};
|
||||
asyncGet();
|
||||
}
|
||||
}, [show]);
|
||||
|
||||
|
||||
const getBody = () => {
|
||||
if(waitingForTrace){
|
||||
return (
|
||||
<WaitingForTraceBody serialNumber={selectedDeviceId} commandUuid={commandUuid}/>
|
||||
);
|
||||
}
|
||||
if(hadSuccess){
|
||||
return(
|
||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>{t('trace.directions')}</h6>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol>
|
||||
<CButton
|
||||
disabled={blockFields}
|
||||
block
|
||||
color="primary"
|
||||
onClick={() => setUsingDuration(true)}
|
||||
>
|
||||
{t('common.duration')}
|
||||
</CButton>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CButton
|
||||
disabled={blockFields}
|
||||
block
|
||||
color="primary"
|
||||
onClick={() => setUsingDuration(false)}
|
||||
>
|
||||
{t('trace.packets')}
|
||||
</CButton>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="4" className={styles.spacedColumn}>
|
||||
{usingDuration ? 'Duration: ' : 'Packets: '}
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
{usingDuration ? (
|
||||
<CSelect defaultValue="duration" disabled={blockFields}>
|
||||
<option value="20" onClick={() => setDuration(20)}>
|
||||
20s
|
||||
</option>
|
||||
<option value="40" onClick={() => setDuration(40)}>
|
||||
40s
|
||||
</option>
|
||||
<option value="60" onClick={() => setDuration(60)}>
|
||||
60s
|
||||
</option>
|
||||
<option value="120" onClick={() => setDuration(120)}>
|
||||
120s
|
||||
</option>
|
||||
</CSelect>
|
||||
) : (
|
||||
<CSelect defaultValue={packets} disabled={blockFields}>
|
||||
<option value="100" onClick={() => setPackets(100)}>
|
||||
100
|
||||
</option>
|
||||
<option value="250" onClick={() => setPackets(250)}>
|
||||
250
|
||||
</option>
|
||||
<option value="500" onClick={() => setPackets(500)}>
|
||||
500
|
||||
</option>
|
||||
<option value="1000" onClick={() => setPackets(1000)}>
|
||||
1000
|
||||
</option>
|
||||
</CSelect>
|
||||
)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="7">{t('trace.choose_network')}:</CCol>
|
||||
<CCol>
|
||||
<CForm>
|
||||
<CFormGroup variant="checkbox" onClick={() => setChosenInterface('up')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenInterface === 'up'}
|
||||
id="traceRadio1"
|
||||
name="radios"
|
||||
value="traceOption1"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="traceRadio1">
|
||||
Up
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setChosenInterface('down')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenInterface === 'down'}
|
||||
id="traceRadio2"
|
||||
name="radios"
|
||||
value="traceOption2"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="traceRadio2">
|
||||
Down
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
</CForm>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>{t('common.execute_now')}</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
disabled={blockFields}
|
||||
color="primary"
|
||||
defaultChecked={isNow}
|
||||
onClick={toggleNow}
|
||||
labelOn={t('common.yes')}
|
||||
labelOff={t('common.no')}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow} hidden={isNow}>
|
||||
<CCol md="4" className={styles.spacedColumn}>
|
||||
<p>{t('common.date')}:</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
selected={new Date(chosenDate)}
|
||||
includeTime
|
||||
value={new Date(chosenDate)}
|
||||
placeholder="Select custom date"
|
||||
disabled={blockFields}
|
||||
onChange={(date) => setDate(date)}
|
||||
min={new Date()}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CInvalidFeedback>{t('common.need_date')}</CInvalidFeedback>
|
||||
<CRow className={styles.spacedRow} hidden={!isNow || !isDeviceConnected}>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>
|
||||
{t('upgrade.wait_for_upgrade')}
|
||||
</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
disabled={blockFields}
|
||||
color="primary"
|
||||
defaultChecked={waitForTrace}
|
||||
onClick={toggleWaitForTrace}
|
||||
labelOn={t('common.yes')}
|
||||
labelOff={t('common.no')}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<div hidden={!hadSuccess && !hadFailure}>
|
||||
<div>
|
||||
<pre className="ignore">{responseBody} </pre>
|
||||
</div>
|
||||
</div>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<LoadingButton
|
||||
label="Schedule"
|
||||
isLoadingLabel="Loading..."
|
||||
isLoading={blockFields}
|
||||
action={doAction}
|
||||
variant="outline"
|
||||
block={false}
|
||||
disabled={blockFields}
|
||||
/>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
{t('common.cancel')}
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<CModal show={show} onClose={toggleModal}>
|
||||
<CModalHeader closeButton>
|
||||
<CModalTitle>{t('trace.title')}</CModalTitle>
|
||||
</CModalHeader>
|
||||
{hadSuccess ? (
|
||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||
) : (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>{t('trace.directions')}</h6>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol>
|
||||
<CButton
|
||||
disabled={waiting}
|
||||
block
|
||||
color="primary"
|
||||
onClick={() => setUsingDuration(true)}
|
||||
>
|
||||
{t('common.duration')}
|
||||
</CButton>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CButton
|
||||
disabled={waiting}
|
||||
block
|
||||
color="primary"
|
||||
onClick={() => setUsingDuration(false)}
|
||||
>
|
||||
{t('trace.packets')}
|
||||
</CButton>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="4" className={styles.spacedColumn}>
|
||||
{usingDuration ? 'Duration: ' : 'Packets: '}
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
{usingDuration ? (
|
||||
<CSelect defaultValue="duration" disabled={waiting}>
|
||||
<option value="20" onClick={() => setDuration(20)}>
|
||||
20s
|
||||
</option>
|
||||
<option value="40" onClick={() => setDuration(40)}>
|
||||
40s
|
||||
</option>
|
||||
<option value="60" onClick={() => setDuration(60)}>
|
||||
60s
|
||||
</option>
|
||||
<option value="120" onClick={() => setDuration(120)}>
|
||||
120s
|
||||
</option>
|
||||
</CSelect>
|
||||
) : (
|
||||
<CSelect defaultValue={packets} disabled={waiting}>
|
||||
<option value="100" onClick={() => setPackets(100)}>
|
||||
100
|
||||
</option>
|
||||
<option value="250" onClick={() => setPackets(250)}>
|
||||
250
|
||||
</option>
|
||||
<option value="500" onClick={() => setPackets(500)}>
|
||||
500
|
||||
</option>
|
||||
<option value="1000" onClick={() => setPackets(1000)}>
|
||||
1000
|
||||
</option>
|
||||
</CSelect>
|
||||
)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="4" className={styles.spacedColumn}>
|
||||
<p>{t('common.date')}:</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
selected={new Date(chosenDate)}
|
||||
includeTime
|
||||
value={new Date(chosenDate)}
|
||||
placeholder="Select custom date"
|
||||
disabled={waiting}
|
||||
onChange={(date) => setDate(date)}
|
||||
min={convertDateToUtc(new Date())}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CInvalidFeedback>{t('common.need_date')}</CInvalidFeedback>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="7">{t('trace.choose_network')}:</CCol>
|
||||
<CCol>
|
||||
<CForm>
|
||||
<CFormGroup variant="checkbox" onClick={() => setChosenInterface('up')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenInterface === 'up'}
|
||||
id="traceRadio1"
|
||||
name="radios"
|
||||
value="traceOption1"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="traceRadio1">
|
||||
Up
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setChosenInterface('down')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenInterface === 'down'}
|
||||
id="traceRadio2"
|
||||
name="radios"
|
||||
value="traceOption2"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="traceRadio2">
|
||||
Down
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
</CForm>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<div hidden={!hadSuccess && !hadFailure}>
|
||||
<div>
|
||||
<pre className="ignore">{responseBody} </pre>
|
||||
</div>
|
||||
</div>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<LoadingButton
|
||||
label="Schedule"
|
||||
isLoadingLabel="Loading..."
|
||||
isLoading={waiting}
|
||||
action={doAction}
|
||||
variant="outline"
|
||||
block={false}
|
||||
disabled={waiting}
|
||||
/>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
{t('common.cancel')}
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</div>
|
||||
)}
|
||||
{getBody()}
|
||||
</CModal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,3 +5,7 @@
|
||||
.spacedColumn {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.centerDiv {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.sidebarImgFull {
|
||||
height: 75px;
|
||||
width: 75px;
|
||||
height: 100px;
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.sidebarImgMinimized {
|
||||
|
||||
16
src/utils/deviceHelper.js
Normal file
16
src/utils/deviceHelper.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
|
||||
export default async (deviceId) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
};
|
||||
|
||||
return axiosInstance
|
||||
.get(`/device/${encodeURIComponent(deviceId)}/status`, options)
|
||||
.then((response) => response.data.connected)
|
||||
.catch(() => false);
|
||||
};
|
||||
Reference in New Issue
Block a user