mirror of
https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
synced 2025-11-02 11:17:46 +00:00
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.5.24",
|
"version": "2.5.27",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.5.24",
|
"version": "2.5.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.5.24",
|
"version": "2.5.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
|
|||||||
@@ -804,6 +804,7 @@
|
|||||||
"mode": "Modus",
|
"mode": "Modus",
|
||||||
"network_diagram": "Netzwerkdiagramm",
|
"network_diagram": "Netzwerkdiagramm",
|
||||||
"radios": "Radios",
|
"radios": "Radios",
|
||||||
"title": "WLAN-Analyse"
|
"title": "WLAN-Analyse",
|
||||||
|
"vendor": "Verkäufer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -804,6 +804,7 @@
|
|||||||
"mode": "Mode",
|
"mode": "Mode",
|
||||||
"network_diagram": "Network Diagram",
|
"network_diagram": "Network Diagram",
|
||||||
"radios": "Radios",
|
"radios": "Radios",
|
||||||
"title": "Wi-Fi Analysis"
|
"title": "Wi-Fi Analysis",
|
||||||
|
"vendor": "Vendor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -804,6 +804,7 @@
|
|||||||
"mode": "Modo",
|
"mode": "Modo",
|
||||||
"network_diagram": "Diagrama de Red",
|
"network_diagram": "Diagrama de Red",
|
||||||
"radios": "Radios",
|
"radios": "Radios",
|
||||||
"title": "Análisis de Wi-Fi"
|
"title": "Análisis de Wi-Fi",
|
||||||
|
"vendor": "Vendedor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -804,6 +804,7 @@
|
|||||||
"mode": "Mode",
|
"mode": "Mode",
|
||||||
"network_diagram": "Diagramme de réseau",
|
"network_diagram": "Diagramme de réseau",
|
||||||
"radios": "Radios",
|
"radios": "Radios",
|
||||||
"title": "Analyse Wi-Fi"
|
"title": "Analyse Wi-Fi",
|
||||||
|
"vendor": "vendeur"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -804,6 +804,7 @@
|
|||||||
"mode": "Modo",
|
"mode": "Modo",
|
||||||
"network_diagram": "Diagrama de rede",
|
"network_diagram": "Diagrama de rede",
|
||||||
"radios": "Rádios",
|
"radios": "Rádios",
|
||||||
"title": "Análise de Wi-Fi"
|
"title": "Análise de Wi-Fi",
|
||||||
|
"vendor": "fornecedor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
CWidgetDropdown,
|
CCardHeader,
|
||||||
CRow,
|
CCardBody,
|
||||||
CCol,
|
|
||||||
CButton,
|
CButton,
|
||||||
CDataTable,
|
CDataTable,
|
||||||
CCard,
|
CCard,
|
||||||
@@ -262,31 +261,47 @@ const DeviceCommands = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<CWidgetDropdown
|
<CCard className="m-0">
|
||||||
className="m-0"
|
<CCardHeader className="dark-header">
|
||||||
inverse="true"
|
<div className="d-flex flex-row-reverse align-items-center">
|
||||||
color="gradient-primary"
|
<div className="pl-2">
|
||||||
header={t('commands.title')}
|
<CPopover content={t('common.refresh')}>
|
||||||
footerSlot={
|
<CButton
|
||||||
<div className="pb-1 px-3">
|
size="sm"
|
||||||
<CRow className="mb-2">
|
color="info"
|
||||||
<CCol>
|
onClick={getCommands}
|
||||||
From:
|
disabled={startError || endError}
|
||||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
>
|
||||||
<CFormText color="danger" hidden={!startError}>
|
<CIcon content={cilSync} />
|
||||||
{t('common.invalid_date_explanation')}
|
</CButton>
|
||||||
</CFormText>
|
</CPopover>
|
||||||
</CCol>
|
</div>
|
||||||
<CCol>
|
<div className="pl-2">
|
||||||
To:
|
<DatePicker
|
||||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
includeTime
|
||||||
|
onChange={(date) => modifyEnd(date)}
|
||||||
|
value={end ? new Date(end) : undefined}
|
||||||
|
/>
|
||||||
<CFormText color="danger" hidden={!endError}>
|
<CFormText color="danger" hidden={!endError}>
|
||||||
{t('common.invalid_date_explanation')}
|
{t('common.invalid_date_explanation')}
|
||||||
</CFormText>
|
</CFormText>
|
||||||
</CCol>
|
</div>
|
||||||
</CRow>
|
To:
|
||||||
<CCard>
|
<div className="pl-2">
|
||||||
<div className="overflow-auto" style={{ height: '200px' }}>
|
<DatePicker
|
||||||
|
includeTime
|
||||||
|
onChange={(date) => modifyStart(date)}
|
||||||
|
value={start ? new Date(start) : undefined}
|
||||||
|
/>
|
||||||
|
<CFormText color="danger" hidden={!startError}>
|
||||||
|
{t('common.invalid_date_explanation')}
|
||||||
|
</CFormText>
|
||||||
|
</div>
|
||||||
|
From:
|
||||||
|
</div>
|
||||||
|
</CCardHeader>
|
||||||
|
<CCardBody className="p-1">
|
||||||
|
<div className="overflow-auto" style={{ height: 'calc(100vh - 620px)' }}>
|
||||||
<CDataTable
|
<CDataTable
|
||||||
addTableClasses="ignore-overflow table-sm"
|
addTableClasses="ignore-overflow table-sm"
|
||||||
border
|
border
|
||||||
@@ -400,17 +415,8 @@ const DeviceCommands = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</CCardBody>
|
||||||
</CCard>
|
</CCard>
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="text-right float-right">
|
|
||||||
<CButton onClick={refreshCommands} size="sm">
|
|
||||||
<CIcon name="cil-sync" content={cilSync} className="text-white" size="2xl" />
|
|
||||||
</CButton>
|
|
||||||
</div>
|
|
||||||
</CWidgetDropdown>
|
|
||||||
|
|
||||||
<WifiScanResultModalWidget
|
<WifiScanResultModalWidget
|
||||||
show={showScanModal}
|
show={showScanModal}
|
||||||
toggle={toggleScanModal}
|
toggle={toggleScanModal}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ 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 'react-widgets/styles.css';
|
import 'react-widgets/styles.css';
|
||||||
import { useAuth, useDevice } from 'ucentral-libs';
|
import { useAuth, useDevice, useToast } from 'ucentral-libs';
|
||||||
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';
|
||||||
@@ -29,6 +29,7 @@ import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
|
|||||||
const ConfigureModal = ({ show, toggleModal }) => {
|
const ConfigureModal = ({ show, toggleModal }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
|
const { addToast } = useToast();
|
||||||
const { deviceSerialNumber } = useDevice();
|
const { deviceSerialNumber } = useDevice();
|
||||||
const [hadSuccess, setHadSuccess] = useState(false);
|
const [hadSuccess, setHadSuccess] = useState(false);
|
||||||
const [hadFailure, setHadFailure] = useState(false);
|
const [hadFailure, setHadFailure] = useState(false);
|
||||||
@@ -91,7 +92,13 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
|||||||
{ headers },
|
{ headers },
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setHadSuccess(true);
|
addToast({
|
||||||
|
title: t('common.success'),
|
||||||
|
body: t('commands.command_success'),
|
||||||
|
color: 'success',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
|
toggleModal();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setResponseBody('Error while submitting command!');
|
setResponseBody('Error while submitting command!');
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
/* eslint-disable-rule prefer-destructuring */
|
/* eslint-disable-rule prefer-destructuring */
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
CWidgetDropdown,
|
CCardBody,
|
||||||
CButton,
|
CButton,
|
||||||
CDataTable,
|
CDataTable,
|
||||||
CCard,
|
CCardHeader,
|
||||||
CRow,
|
|
||||||
CCol,
|
|
||||||
CProgress,
|
|
||||||
CPopover,
|
CPopover,
|
||||||
|
CCard,
|
||||||
|
CFormText,
|
||||||
|
CBadge,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import { cilTrash } from '@coreui/icons';
|
import { cilSync, cilTrash } from '@coreui/icons';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
import { dateToUnix } from 'utils/helper';
|
import { dateToUnix } from 'utils/helper';
|
||||||
@@ -27,7 +27,9 @@ const DeviceHealth = () => {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [healthChecks, setHealthChecks] = useState([]);
|
const [healthChecks, setHealthChecks] = useState([]);
|
||||||
const [start, setStart] = useState('');
|
const [start, setStart] = useState('');
|
||||||
|
const [startError, setStartError] = useState(false);
|
||||||
const [end, setEnd] = useState('');
|
const [end, setEnd] = useState('');
|
||||||
|
const [endError, setEndError] = useState(false);
|
||||||
const [logLimit, setLogLimit] = useState(25);
|
const [logLimit, setLogLimit] = useState(25);
|
||||||
const [loadingMore, setLoadingMore] = useState(false);
|
const [loadingMore, setLoadingMore] = useState(false);
|
||||||
const [showLoadingMore, setShowLoadingMore] = useState(true);
|
const [showLoadingMore, setShowLoadingMore] = useState(true);
|
||||||
@@ -40,13 +42,26 @@ const DeviceHealth = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const modifyStart = (value) => {
|
const modifyStart = (value) => {
|
||||||
|
try {
|
||||||
|
new Date(value).toISOString();
|
||||||
|
setStartError(false);
|
||||||
setStart(value);
|
setStart(value);
|
||||||
|
} catch (e) {
|
||||||
|
setStart('');
|
||||||
|
setStartError(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const modifyEnd = (value) => {
|
const modifyEnd = (value) => {
|
||||||
|
try {
|
||||||
|
new Date(value).toISOString();
|
||||||
|
setEndError(false);
|
||||||
setEnd(value);
|
setEnd(value);
|
||||||
|
} catch (e) {
|
||||||
|
setEnd('');
|
||||||
|
setEndError(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showMoreLogs = () => {
|
const showMoreLogs = () => {
|
||||||
setLogLimit(logLimit + 50);
|
setLogLimit(logLimit + 50);
|
||||||
};
|
};
|
||||||
@@ -128,14 +143,14 @@ const DeviceHealth = () => {
|
|||||||
const tempSanityLevel = sortedHealthchecks[healthChecks.length - 1].sanity;
|
const tempSanityLevel = sortedHealthchecks[healthChecks.length - 1].sanity;
|
||||||
setSanityLevel(tempSanityLevel);
|
setSanityLevel(tempSanityLevel);
|
||||||
if (tempSanityLevel === 100) {
|
if (tempSanityLevel === 100) {
|
||||||
setBarColor('gradient-success');
|
setBarColor('success');
|
||||||
} else if (tempSanityLevel >= 90) {
|
} else if (tempSanityLevel >= 90) {
|
||||||
setBarColor('gradient-warning');
|
setBarColor('warning');
|
||||||
} else {
|
} else {
|
||||||
setBarColor('gradient-danger');
|
setBarColor('danger');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setBarColor('gradient-dark');
|
setBarColor('dark');
|
||||||
}
|
}
|
||||||
}, [healthChecks]);
|
}, [healthChecks]);
|
||||||
|
|
||||||
@@ -156,30 +171,61 @@ const DeviceHealth = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CWidgetDropdown
|
<CCard className="m-0">
|
||||||
className="m-0"
|
<CCardHeader className="dark-header">
|
||||||
header={t('health.title')}
|
<div className="float-left align-middle pt-1">
|
||||||
text={sanityLevel ? `${sanityLevel}%` : t('common.unknown')}
|
<h4>
|
||||||
value={sanityLevel ?? 100}
|
<CBadge color={barColor} className="my-0">
|
||||||
color={barColor}
|
{sanityLevel ? `${sanityLevel}%` : `${t('common.unknown')} Sanity Level`}
|
||||||
inverse="true"
|
</CBadge>
|
||||||
footerSlot={
|
</h4>
|
||||||
<div className="pb-1 px-3">
|
</div>
|
||||||
<CProgress className="mb-3" color="white" value={sanityLevel ?? 0} />
|
<div className="d-flex flex-row-reverse align-items-center">
|
||||||
<CRow className="mb-3">
|
<div className="pl-2">
|
||||||
<CCol>
|
<CPopover content={t('common.refresh')}>
|
||||||
{t('common.from')}
|
<CButton
|
||||||
:
|
size="sm"
|
||||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
color="info"
|
||||||
</CCol>
|
onClick={getDeviceHealth}
|
||||||
<CCol>
|
disabled={startError || endError}
|
||||||
{t('common.to')}
|
>
|
||||||
:
|
<CIcon content={cilSync} />
|
||||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
</CButton>
|
||||||
</CCol>
|
</CPopover>
|
||||||
</CRow>
|
</div>
|
||||||
<CCard className="p-0">
|
<div className="pl-2">
|
||||||
<div className="overflow-auto" style={{ height: '200px' }}>
|
<DatePicker
|
||||||
|
includeTime
|
||||||
|
onChange={(date) => modifyEnd(date)}
|
||||||
|
value={end ? new Date(end) : undefined}
|
||||||
|
/>
|
||||||
|
<CFormText color="danger" hidden={!endError}>
|
||||||
|
{t('common.invalid_date_explanation')}
|
||||||
|
</CFormText>
|
||||||
|
</div>
|
||||||
|
To:
|
||||||
|
<div className="pl-2">
|
||||||
|
<DatePicker
|
||||||
|
includeTime
|
||||||
|
onChange={(date) => modifyStart(date)}
|
||||||
|
value={start ? new Date(start) : undefined}
|
||||||
|
/>
|
||||||
|
<CFormText color="danger" hidden={!startError}>
|
||||||
|
{t('common.invalid_date_explanation')}
|
||||||
|
</CFormText>
|
||||||
|
</div>
|
||||||
|
From:
|
||||||
|
<div className="px-2">
|
||||||
|
<CPopover content={t('common.delete')}>
|
||||||
|
<CButton onClick={toggleDeleteModal} size="sm" color="danger">
|
||||||
|
<CIcon name="cil-trash" content={cilTrash} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CCardHeader>
|
||||||
|
<CCardBody className="p-1">
|
||||||
|
<div className="overflow-auto" style={{ height: 'calc(100vh - 620px)' }}>
|
||||||
<CDataTable
|
<CDataTable
|
||||||
addTableClasses="ignore-overflow table-sm"
|
addTableClasses="ignore-overflow table-sm"
|
||||||
border
|
border
|
||||||
@@ -214,25 +260,15 @@ const DeviceHealth = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
</CCard>
|
|
||||||
<DeleteLogModal
|
<DeleteLogModal
|
||||||
serialNumber={deviceSerialNumber}
|
serialNumber={deviceSerialNumber}
|
||||||
object="healthchecks"
|
object="logs"
|
||||||
show={showDeleteModal}
|
show={showDeleteModal}
|
||||||
toggle={toggleDeleteModal}
|
toggle={toggleDeleteModal}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
</CCardBody>
|
||||||
>
|
</CCard>
|
||||||
<div className="text-right float-right">
|
|
||||||
<CPopover content={t('common.delete')}>
|
|
||||||
<CButton onClick={toggleDeleteModal} size="sm">
|
|
||||||
<CIcon name="cil-trash" content={cilTrash} className="text-white" size="2xl" />
|
|
||||||
</CButton>
|
|
||||||
</CPopover>
|
|
||||||
</div>
|
|
||||||
</CWidgetDropdown>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
/* eslint-disable-rule prefer-destructuring */
|
/* eslint-disable-rule prefer-destructuring */
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
CWidgetDropdown,
|
CCardHeader,
|
||||||
CRow,
|
CCardBody,
|
||||||
CCol,
|
|
||||||
CCollapse,
|
CCollapse,
|
||||||
CButton,
|
CButton,
|
||||||
CDataTable,
|
CDataTable,
|
||||||
CCard,
|
CCard,
|
||||||
CCardBody,
|
|
||||||
CPopover,
|
CPopover,
|
||||||
|
CFormText,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import { cilTrash } from '@coreui/icons';
|
import { cilSync, cilTrash } from '@coreui/icons';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
import { dateToUnix } from 'utils/helper';
|
import { dateToUnix } from 'utils/helper';
|
||||||
@@ -29,7 +28,9 @@ const DeviceLogs = () => {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [logs, setLogs] = useState([]);
|
const [logs, setLogs] = useState([]);
|
||||||
const [start, setStart] = useState('');
|
const [start, setStart] = useState('');
|
||||||
|
const [startError, setStartError] = useState(false);
|
||||||
const [end, setEnd] = useState('');
|
const [end, setEnd] = useState('');
|
||||||
|
const [endError, setEndError] = useState(false);
|
||||||
const [logLimit, setLogLimit] = useState(25);
|
const [logLimit, setLogLimit] = useState(25);
|
||||||
const [loadingMore, setLoadingMore] = useState(false);
|
const [loadingMore, setLoadingMore] = useState(false);
|
||||||
const [showLoadingMore, setShowLoadingMore] = useState(true);
|
const [showLoadingMore, setShowLoadingMore] = useState(true);
|
||||||
@@ -40,11 +41,25 @@ const DeviceLogs = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const modifyStart = (value) => {
|
const modifyStart = (value) => {
|
||||||
|
try {
|
||||||
|
new Date(value).toISOString();
|
||||||
|
setStartError(false);
|
||||||
setStart(value);
|
setStart(value);
|
||||||
|
} catch (e) {
|
||||||
|
setStart('');
|
||||||
|
setStartError(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const modifyEnd = (value) => {
|
const modifyEnd = (value) => {
|
||||||
|
try {
|
||||||
|
new Date(value).toISOString();
|
||||||
|
setEndError(false);
|
||||||
setEnd(value);
|
setEnd(value);
|
||||||
|
} catch (e) {
|
||||||
|
setEnd('');
|
||||||
|
setEndError(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showMoreLogs = () => {
|
const showMoreLogs = () => {
|
||||||
@@ -167,25 +182,49 @@ const DeviceLogs = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<CWidgetDropdown
|
<CCard className="m-0">
|
||||||
className="m-0"
|
<CCardHeader className="dark-header">
|
||||||
inverse="true"
|
<div className="d-flex flex-row-reverse align-items-center">
|
||||||
color="gradient-info"
|
<div className="pl-2">
|
||||||
header={t('device_logs.title')}
|
<CPopover content={t('common.refresh')}>
|
||||||
footerSlot={
|
<CButton size="sm" color="info" onClick={getLogs} disabled={startError || endError}>
|
||||||
<div className="pb-1 px-3">
|
<CIcon content={cilSync} />
|
||||||
<CRow className="mb-3">
|
</CButton>
|
||||||
<CCol>
|
</CPopover>
|
||||||
{t('common.from')}
|
</div>
|
||||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
<div className="pl-2">
|
||||||
</CCol>
|
<DatePicker
|
||||||
<CCol>
|
includeTime
|
||||||
{t('common.to')}
|
onChange={(date) => modifyEnd(date)}
|
||||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
value={end ? new Date(end) : undefined}
|
||||||
</CCol>
|
/>
|
||||||
</CRow>
|
<CFormText color="danger" hidden={!endError}>
|
||||||
<CCard>
|
{t('common.invalid_date_explanation')}
|
||||||
<div className="overflow-auto" style={{ height: '250px' }}>
|
</CFormText>
|
||||||
|
</div>
|
||||||
|
To:
|
||||||
|
<div className="pl-2">
|
||||||
|
<DatePicker
|
||||||
|
includeTime
|
||||||
|
onChange={(date) => modifyStart(date)}
|
||||||
|
value={start ? new Date(start) : undefined}
|
||||||
|
/>
|
||||||
|
<CFormText color="danger" hidden={!startError}>
|
||||||
|
{t('common.invalid_date_explanation')}
|
||||||
|
</CFormText>
|
||||||
|
</div>
|
||||||
|
From:
|
||||||
|
<div className="px-2">
|
||||||
|
<CPopover content={t('common.delete')}>
|
||||||
|
<CButton onClick={toggleDeleteModal} size="sm" color="danger">
|
||||||
|
<CIcon name="cil-trash" content={cilTrash} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CCardHeader>
|
||||||
|
<CCardBody className="p-1">
|
||||||
|
<div className="overflow-auto" style={{ height: 'calc(100vh - 620px)' }}>
|
||||||
<CDataTable
|
<CDataTable
|
||||||
addTableClasses="ignore-overflow table-sm"
|
addTableClasses="ignore-overflow table-sm"
|
||||||
border
|
border
|
||||||
@@ -240,18 +279,8 @@ const DeviceLogs = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</CCardBody>
|
||||||
</CCard>
|
</CCard>
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="text-right float-right">
|
|
||||||
<CPopover content={t('common.delete')}>
|
|
||||||
<CButton onClick={toggleDeleteModal} size="sm">
|
|
||||||
<CIcon name="cil-trash" content={cilTrash} className="text-white" size="2xl" />
|
|
||||||
</CButton>
|
|
||||||
</CPopover>
|
|
||||||
</div>
|
|
||||||
</CWidgetDropdown>
|
|
||||||
<DeleteLogModal
|
<DeleteLogModal
|
||||||
serialNumber={deviceSerialNumber}
|
serialNumber={deviceSerialNumber}
|
||||||
object="logs"
|
object="logs"
|
||||||
|
|||||||
@@ -22,10 +22,11 @@ const WifiAnalysisTable = ({ t, data, loading }) => {
|
|||||||
setShow(!show);
|
setShow(!show);
|
||||||
};
|
};
|
||||||
const columns = [
|
const columns = [
|
||||||
{ key: 'radio', label: '#', _style: { width: '5%' } },
|
{ key: 'radio', label: '#', _style: { width: '1%' } },
|
||||||
{ key: 'bssid', label: 'BSSID', _style: { width: '14%' } },
|
{ key: 'bssid', label: 'BSSID', _style: { width: '1%' } },
|
||||||
{ key: 'mode', label: t('wifi_analysis.mode'), _style: { width: '9%' }, sorter: false },
|
{ key: 'vendor', label: t('wifi_analysis.vendor'), _style: { width: '15%' }, sorter: false },
|
||||||
{ key: 'ssid', label: 'SSID', _style: { width: '17%' } },
|
{ key: 'mode', label: t('wifi_analysis.mode'), _style: { width: '1%' }, sorter: false },
|
||||||
|
{ key: 'ssid', label: 'SSID', _style: { width: '15%' } },
|
||||||
{ key: 'rssi', label: 'RSSI', _style: { width: '5%' }, sorter: false },
|
{ key: 'rssi', label: 'RSSI', _style: { width: '5%' }, sorter: false },
|
||||||
{ key: 'rxRate', label: 'Rx Rate', _style: { width: '7%' }, sorter: false },
|
{ key: 'rxRate', label: 'Rx Rate', _style: { width: '7%' }, sorter: false },
|
||||||
{ key: 'rxBytes', label: 'Rx', _style: { width: '7%' }, sorter: false },
|
{ key: 'rxBytes', label: 'Rx', _style: { width: '7%' }, sorter: false },
|
||||||
@@ -33,26 +34,39 @@ const WifiAnalysisTable = ({ t, data, loading }) => {
|
|||||||
{ key: 'rxNss', label: 'Rx NSS', _style: { width: '6%' }, sorter: false },
|
{ key: 'rxNss', label: 'Rx NSS', _style: { width: '6%' }, sorter: false },
|
||||||
{ key: 'txRate', label: 'Tx Rate', _style: { width: '7%' }, sorter: false },
|
{ key: 'txRate', label: 'Tx Rate', _style: { width: '7%' }, sorter: false },
|
||||||
{ key: 'txBytes', label: 'Tx', _style: { width: '7%' }, sorter: false },
|
{ key: 'txBytes', label: 'Tx', _style: { width: '7%' }, sorter: false },
|
||||||
{ key: 'ips', label: 'IP', _style: { width: '6%' }, sorter: false },
|
{ key: 'ips', label: 'IP', _style: { width: '1%' }, sorter: false },
|
||||||
];
|
];
|
||||||
|
|
||||||
const centerIfEmpty = (value) => (
|
const centerIfEmpty = (value) => (
|
||||||
<td className={!value || value === '' || value === '-' ? 'text-center' : ''}>{value}</td>
|
<td
|
||||||
|
className={
|
||||||
|
!value || value === '' || value === '-'
|
||||||
|
? 'text-center align-middle'
|
||||||
|
: 'text-right align-middle'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</td>
|
||||||
);
|
);
|
||||||
|
|
||||||
const displayIp = (ssid, v4, v6) => {
|
const displayIp = (ssid, v4, v6) => {
|
||||||
const count = v4.length + v6.length;
|
const count = v4.length + v6.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<td className="ignore-overflow text-center">
|
<td className="ignore-overflow text-center align-middle">
|
||||||
{count > 0 ? (
|
{count > 0 ? (
|
||||||
<CPopover content="View">
|
<CPopover content="View">
|
||||||
<CButton color="primary" size="sm" onClick={() => toggle(ssid, v4, v6)}>
|
<CButton
|
||||||
|
color="primary"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => toggle(ssid, v4, v6)}
|
||||||
|
className="py-1"
|
||||||
|
>
|
||||||
{count}
|
{count}
|
||||||
</CButton>
|
</CButton>
|
||||||
</CPopover>
|
</CPopover>
|
||||||
) : (
|
) : (
|
||||||
<p>{count}</p>
|
count
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
@@ -70,8 +84,23 @@ const WifiAnalysisTable = ({ t, data, loading }) => {
|
|||||||
sorter
|
sorter
|
||||||
sorterValue={{ column: 'radio', asc: true }}
|
sorterValue={{ column: 'radio', asc: true }}
|
||||||
scopedSlots={{
|
scopedSlots={{
|
||||||
radio: (item) => <td className="text-center">{item.radio.radio}</td>,
|
bssid: (item) => (
|
||||||
|
<td
|
||||||
|
className="text-center align-middle"
|
||||||
|
style={{ fontFamily: 'monospace', fontSize: '0.96rem' }}
|
||||||
|
>
|
||||||
|
{item.bssid}
|
||||||
|
</td>
|
||||||
|
),
|
||||||
|
radio: (item) => <td className="text-center align-middle">{item.radio.radio}</td>,
|
||||||
|
ssid: (item) => <td className="align-middle">{item.ssid}</td>,
|
||||||
|
mode: (item) => <td className="align-middle">{item.mode}</td>,
|
||||||
|
vendor: (item) => <td className="align-middle">{item.vendor}</td>,
|
||||||
rxMcs: (item) => centerIfEmpty(item.rxMcs),
|
rxMcs: (item) => centerIfEmpty(item.rxMcs),
|
||||||
|
rxRate: (item) => centerIfEmpty(item.rxRate),
|
||||||
|
rxBytes: (item) => centerIfEmpty(item.rxBytes),
|
||||||
|
txRate: (item) => centerIfEmpty(item.txRate),
|
||||||
|
txBytes: (item) => centerIfEmpty(item.txBytes),
|
||||||
rxNss: (item) => centerIfEmpty(item.rxNss),
|
rxNss: (item) => centerIfEmpty(item.rxNss),
|
||||||
rssi: (item) => centerIfEmpty(item.rssi),
|
rssi: (item) => centerIfEmpty(item.rssi),
|
||||||
ips: (item) => displayIp(item.ssid, item.ipV4, item.ipV6),
|
ips: (item) => displayIp(item.ssid, item.ipV4, item.ipV6),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
CPopover,
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import { cilX } from '@coreui/icons';
|
import { cilSync, cilX } from '@coreui/icons';
|
||||||
import RadioAnalysisTable from './RadioAnalysis';
|
import RadioAnalysisTable from './RadioAnalysis';
|
||||||
import WifiAnalysisTable from './WifiAnalysis';
|
import WifiAnalysisTable from './WifiAnalysis';
|
||||||
|
|
||||||
@@ -67,9 +67,33 @@ const WifiAnalysis = () => {
|
|||||||
return ips;
|
return ips;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseAssociationStats = (json) => {
|
const getVendors = async (bssids) => {
|
||||||
|
setLoading(true);
|
||||||
|
setRange(19);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${currentToken}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return axiosInstance
|
||||||
|
.get(`${endpoints.owgw}/api/v1/ouis?macList=${bssids.join(',')}`, options)
|
||||||
|
.then((response) => {
|
||||||
|
const newObj = bssids;
|
||||||
|
for (const tag of response.data.tagList) {
|
||||||
|
newObj[tag.tag] = tag.value === '' ? '-' : tag.value;
|
||||||
|
}
|
||||||
|
return newObj;
|
||||||
|
})
|
||||||
|
.catch(() => ({}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseAssociationStats = async (json) => {
|
||||||
const newParsedAssociationStats = [];
|
const newParsedAssociationStats = [];
|
||||||
const newParsedRadioStats = [];
|
const newParsedRadioStats = [];
|
||||||
|
const bssidObj = {};
|
||||||
|
|
||||||
for (const stat of json.data) {
|
for (const stat of json.data) {
|
||||||
const associations = [];
|
const associations = [];
|
||||||
@@ -123,6 +147,8 @@ const WifiAnalysis = () => {
|
|||||||
|
|
||||||
if ('associations' in ssid) {
|
if ('associations' in ssid) {
|
||||||
for (const association of ssid.associations) {
|
for (const association of ssid.associations) {
|
||||||
|
bssidObj[association.bssid] = 0;
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
radio: radioInfo,
|
radio: radioInfo,
|
||||||
...extractIp(stat.data, association.bssid),
|
...extractIp(stat.data, association.bssid),
|
||||||
@@ -149,6 +175,16 @@ const WifiAnalysis = () => {
|
|||||||
newParsedAssociationStats.push(associations);
|
newParsedAssociationStats.push(associations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adding Vendor info to associations
|
||||||
|
const vendors = await getVendors(Object.keys(bssidObj));
|
||||||
|
|
||||||
|
for (let i = 0; i < newParsedAssociationStats.length; i += 1) {
|
||||||
|
for (let y = 0; y < newParsedAssociationStats[i].length; y += 1) {
|
||||||
|
newParsedAssociationStats[i][y].vendor =
|
||||||
|
vendors[newParsedAssociationStats[i][y].bssid] ?? '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Radio Stats
|
// Radio Stats
|
||||||
const ascOrderedRadioStats = newParsedRadioStats.reverse();
|
const ascOrderedRadioStats = newParsedRadioStats.reverse();
|
||||||
setParsedRadioStats(ascOrderedRadioStats);
|
setParsedRadioStats(ascOrderedRadioStats);
|
||||||
@@ -203,14 +239,19 @@ const WifiAnalysis = () => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<CCard>
|
<CCard>
|
||||||
<CCardHeader className="dark-header">
|
<CCardHeader className="dark-header d-flex flex-row-reverse align-items-center">
|
||||||
<CRow>
|
<div className="pl-2">
|
||||||
<CCol className="text-right">
|
<CPopover content={t('common.refresh')}>
|
||||||
|
<CButton size="sm" color="info" onClick={getLatestAssociationStats}>
|
||||||
|
<CIcon content={cilSync} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<CButton color="info" size="sm" onClick={toggleModal}>
|
<CButton color="info" size="sm" onClick={toggleModal}>
|
||||||
{t('wifi_analysis.network_diagram')}
|
{t('wifi_analysis.network_diagram')}
|
||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</div>
|
||||||
</CRow>
|
|
||||||
</CCardHeader>
|
</CCardHeader>
|
||||||
<CCardBody>
|
<CCardBody>
|
||||||
<CRow className="mb-4">
|
<CRow className="mb-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user