mirror of
https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
synced 2025-10-30 01:42:19 +00:00
Merge pull request #58 from stephb9959/bug/54-improved-post-action-experience
Bug/54 improved post action experience
This commit is contained in:
@@ -2,8 +2,23 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CButton, CSpinner } from '@coreui/react';
|
||||
|
||||
const LoadingButton = ({ isLoading, label, isLoadingLabel, action, color, variant}) => (
|
||||
<CButton variant={variant} disabled={isLoading} color={color} onClick={() => action()} block>
|
||||
const LoadingButton = ({
|
||||
isLoading,
|
||||
label,
|
||||
isLoadingLabel,
|
||||
action,
|
||||
color,
|
||||
variant,
|
||||
block,
|
||||
disabled,
|
||||
}) => (
|
||||
<CButton
|
||||
variant={variant}
|
||||
color={color}
|
||||
onClick={() => action()}
|
||||
block={block}
|
||||
disabled={isLoading || disabled}
|
||||
>
|
||||
{isLoading ? isLoadingLabel : label}
|
||||
<CSpinner hidden={!isLoading} component="span" size="sm" />
|
||||
</CButton>
|
||||
@@ -11,16 +26,20 @@ const LoadingButton = ({ isLoading, label, isLoadingLabel, action, color, varian
|
||||
|
||||
LoadingButton.propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
block: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
label: PropTypes.string.isRequired,
|
||||
isLoadingLabel: PropTypes.string.isRequired,
|
||||
action: PropTypes.func.isRequired,
|
||||
color: PropTypes.string,
|
||||
variant: PropTypes.string
|
||||
variant: PropTypes.string,
|
||||
};
|
||||
|
||||
LoadingButton.defaultProps = {
|
||||
color: "primary",
|
||||
variant: ""
|
||||
}
|
||||
color: 'primary',
|
||||
variant: '',
|
||||
block: true,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export default LoadingButton;
|
||||
|
||||
22
src/components/SuccessfulActionModalBody.js
Normal file
22
src/components/SuccessfulActionModalBody.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CButton, CModalBody, CModalFooter } from '@coreui/react';
|
||||
|
||||
const SuccessfulActionModalBody = ({ toggleModal }) => (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>Command submitted successfully</h6>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<CButton variant="outline" color="primary" onClick={() => toggleModal()} block>
|
||||
Dismiss
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</div>
|
||||
);
|
||||
|
||||
SuccessfulActionModalBody.propTypes = {
|
||||
toggleModal: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default SuccessfulActionModalBody;
|
||||
@@ -3,7 +3,7 @@ import { CFooter } from '@coreui/react';
|
||||
|
||||
const TheFooter = () => (
|
||||
<CFooter fixed={false}>
|
||||
<div>Version 0.0.11</div>
|
||||
<div>Version 0.0.12</div>
|
||||
<div className="mfs-auto">
|
||||
<span className="mr-1">Powered by</span>
|
||||
<a href="https://coreui.io/react" target="_blank" rel="noopener noreferrer">
|
||||
|
||||
@@ -66,7 +66,10 @@ const DeviceList = () => {
|
||||
|
||||
const startIndex = page * devicesPerPage;
|
||||
const endIndex = parseInt(startIndex, 10) + parseInt(devicesPerPage, 10);
|
||||
const serialsToGet = serialNumbers.slice(startIndex, endIndex).map(x => encodeURIComponent(x)).join(',');
|
||||
const serialsToGet = serialNumbers
|
||||
.slice(startIndex, endIndex)
|
||||
.map((x) => encodeURIComponent(x))
|
||||
.join(',');
|
||||
|
||||
axiosInstance
|
||||
.get(`/devices?deviceWithStatus=true&select=${serialsToGet}`, {
|
||||
|
||||
@@ -19,6 +19,8 @@ import 'react-widgets/styles.css';
|
||||
import { getToken } from '../../utils/authHelper';
|
||||
import axiosInstance from '../../utils/axiosInstance';
|
||||
import eventBus from '../../utils/EventBus';
|
||||
import LoadingButton from '../../components/LoadingButton';
|
||||
import SuccessfulActionModalBody from '../../components/SuccessfulActionModalBody';
|
||||
|
||||
const ActionModal = ({ show, toggleModal, title, directions, action }) => {
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
@@ -28,17 +30,8 @@ const ActionModal = ({ show, toggleModal, title, directions, action }) => {
|
||||
const [chosenDate, setChosenDate] = useState(new Date().toString());
|
||||
const [doingNow, setDoingNow] = useState(false);
|
||||
const [responseBody, setResponseBody] = useState('');
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const formValidation = () => {
|
||||
if (chosenDate === '') {
|
||||
setValidDate(false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const setDateToLate = () => {
|
||||
const date = convertDateToUtc(new Date());
|
||||
if (date.getHours() >= 3) {
|
||||
@@ -56,23 +49,20 @@ const ActionModal = ({ show, toggleModal, title, directions, action }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const confirmingIfSure = () => {
|
||||
setCheckingIfSure(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setDoingNow(false);
|
||||
setChosenDate(new Date().toString());
|
||||
setResponseBody('');
|
||||
setValidDate(true);
|
||||
setCheckingIfSure(false);
|
||||
if (show) {
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setDoingNow(false);
|
||||
setChosenDate(new Date().toString());
|
||||
setResponseBody('');
|
||||
setValidDate(true);
|
||||
}
|
||||
}, [show]);
|
||||
|
||||
const doAction = (isNow) => {
|
||||
setDoingNow(isNow);
|
||||
if (isNow !== undefined) setDoingNow(isNow);
|
||||
setHadFailure(false);
|
||||
setHadSuccess(false);
|
||||
setWaiting(true);
|
||||
@@ -103,7 +93,6 @@ const ActionModal = ({ show, toggleModal, title, directions, action }) => {
|
||||
})
|
||||
.finally(() => {
|
||||
setDoingNow(false);
|
||||
setCheckingIfSure(false);
|
||||
setWaiting(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
});
|
||||
@@ -114,69 +103,66 @@ const ActionModal = ({ show, toggleModal, title, directions, action }) => {
|
||||
<CModalHeader closeButton>
|
||||
<CModalTitle>{title}</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CModalBody>
|
||||
<h6>{directions}</h6>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol>
|
||||
<CButton onClick={() => doAction(true)} disabled={waiting} block color="primary">
|
||||
{waiting && doingNow ? 'Loading...' : 'Do Now!'}
|
||||
<CSpinner hidden={!waiting || !doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CButton disabled={waiting} block color="primary" onClick={() => setDateToLate()}>
|
||||
Later tonight
|
||||
</CButton>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol md="4" style={{ marginTop: '7px' }}>
|
||||
<p>Date:</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
selected={new Date(chosenDate)}
|
||||
includeTime
|
||||
className={('form-control', { 'is-invalid': !validDate })}
|
||||
value={new Date(chosenDate)}
|
||||
placeholder="Select custom date"
|
||||
disabled={waiting}
|
||||
onChange={(date) => setDate(date)}
|
||||
min={convertDateToUtc(new Date())}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CInvalidFeedback>You need a date...</CInvalidFeedback>
|
||||
{hadSuccess ? (
|
||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||
) : (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>{directions}</h6>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol>
|
||||
<CButton onClick={() => doAction(true)} disabled={waiting} block color="primary">
|
||||
{waiting && doingNow ? 'Loading...' : 'Do Now!'}
|
||||
<CSpinner hidden={!waiting || !doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CButton disabled={waiting} block color="primary" onClick={() => setDateToLate()}>
|
||||
Later tonight
|
||||
</CButton>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol md="4" style={{ marginTop: '7px' }}>
|
||||
<p>Date:</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
selected={new Date(chosenDate)}
|
||||
includeTime
|
||||
className={('form-control', { 'is-invalid': !validDate })}
|
||||
value={new Date(chosenDate)}
|
||||
placeholder="Select custom date"
|
||||
disabled={waiting}
|
||||
onChange={(date) => setDate(date)}
|
||||
min={convertDateToUtc(new Date())}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CInvalidFeedback>You need a date...</CInvalidFeedback>
|
||||
|
||||
<div hidden={!hadSuccess && !hadFailure}>
|
||||
<div>
|
||||
<pre className="ignore">{responseBody}</pre>
|
||||
</div>
|
||||
<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}>
|
||||
Cancel
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</div>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<div hidden={!checkingIfSure}>Are you sure?</div>
|
||||
<CButton
|
||||
hidden={checkingIfSure}
|
||||
disabled={waiting}
|
||||
color="primary"
|
||||
onClick={() => (formValidation() ? confirmingIfSure() : null)}
|
||||
>
|
||||
Schedule
|
||||
</CButton>
|
||||
<CButton
|
||||
hidden={!checkingIfSure}
|
||||
disabled={waiting}
|
||||
color="primary"
|
||||
onClick={() => (formValidation() ? doAction(false) : null)}
|
||||
>
|
||||
{waiting && !doingNow ? 'Loading...' : 'Yes'} {' '}
|
||||
<CSpinner hidden={!waiting || doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
Cancel
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
)}
|
||||
</CModal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -22,6 +22,8 @@ import 'react-widgets/styles.css';
|
||||
import { getToken } from '../../utils/authHelper';
|
||||
import axiosInstance from '../../utils/axiosInstance';
|
||||
import eventBus from '../../utils/EventBus';
|
||||
import SuccessfulActionModalBody from '../../components/SuccessfulActionModalBody';
|
||||
import LoadingButton from '../../components/LoadingButton';
|
||||
|
||||
const BlinkModal = ({ show, toggleModal }) => {
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
@@ -31,7 +33,6 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
const [chosenDate, setChosenDate] = useState(new Date().toString());
|
||||
const [chosenPattern, setPattern] = useState('on');
|
||||
const [responseBody, setResponseBody] = useState('');
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const setDateToLate = () => {
|
||||
@@ -51,23 +52,20 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const confirmingIfSure = () => {
|
||||
setCheckingIfSure(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setChosenDate(new Date().toString());
|
||||
setResponseBody('');
|
||||
setPattern('on');
|
||||
setCheckingIfSure(false);
|
||||
setDoingNow(false);
|
||||
if (show) {
|
||||
setWaiting(false);
|
||||
setChosenDate(new Date().toString());
|
||||
setResponseBody('');
|
||||
setPattern('on');
|
||||
setDoingNow(false);
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
}
|
||||
}, [show]);
|
||||
|
||||
const doAction = (isNow) => {
|
||||
setDoingNow(isNow);
|
||||
if (isNow !== undefined) setDoingNow(isNow);
|
||||
setHadFailure(false);
|
||||
setHadSuccess(false);
|
||||
setWaiting(true);
|
||||
@@ -100,7 +98,6 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
})
|
||||
.finally(() => {
|
||||
setDoingNow(false);
|
||||
setCheckingIfSure(false);
|
||||
setWaiting(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
});
|
||||
@@ -111,106 +108,103 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
<CModalHeader closeButton>
|
||||
<CModalTitle>LEDs of Device</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CModalBody>
|
||||
<h6>When would you like make the LEDs of this device blink?</h6>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol>
|
||||
<CButton onClick={() => doAction(true)} disabled={waiting} block color="primary">
|
||||
{waiting && doingNow ? 'Loading...' : 'Do Now!'}
|
||||
<CSpinner hidden={!waiting || !doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CButton disabled={waiting} block color="primary" onClick={() => setDateToLate()}>
|
||||
Later tonight
|
||||
</CButton>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol md="4" style={{ marginTop: '7px' }}>
|
||||
<p>Date:</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
selected={new Date(chosenDate)}
|
||||
includeTime
|
||||
value={new Date(chosenDate)}
|
||||
placeholder="Select custom date"
|
||||
{hadSuccess ? (
|
||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||
) : (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>When would you like make the LEDs of this device blink?</h6>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol>
|
||||
<CButton onClick={() => doAction(true)} disabled={waiting} block color="primary">
|
||||
{waiting && doingNow ? 'Loading...' : 'Do Now!'}
|
||||
<CSpinner hidden={!waiting || !doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CButton disabled={waiting} block color="primary" onClick={() => setDateToLate()}>
|
||||
Later tonight
|
||||
</CButton>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol md="4" style={{ marginTop: '7px' }}>
|
||||
<p>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>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol md="7">Choose a pattern you would like to use:</CCol>
|
||||
<CCol>
|
||||
<CForm>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('on')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'on'}
|
||||
id="radio1"
|
||||
name="radios"
|
||||
value="option1"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio1">
|
||||
On
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('off')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'off'}
|
||||
id="radio2"
|
||||
name="radios"
|
||||
value="option2"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio2">
|
||||
Off
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('blink')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'blink'}
|
||||
id="radio2"
|
||||
name="radios"
|
||||
value="option2"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio2">
|
||||
Blink
|
||||
</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 && !doingNow}
|
||||
action={doAction}
|
||||
variant="outline"
|
||||
block={false}
|
||||
disabled={waiting}
|
||||
onChange={(date) => setDate(date)}
|
||||
min={convertDateToUtc(new Date())}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol md="7">Choose a pattern you would like to use:</CCol>
|
||||
<CCol>
|
||||
<CForm>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('on')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'on'}
|
||||
id="radio1"
|
||||
name="radios"
|
||||
value="option1"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio1">
|
||||
On
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('off')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'off'}
|
||||
id="radio2"
|
||||
name="radios"
|
||||
value="option2"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio2">
|
||||
Off
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('blink')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'blink'}
|
||||
id="radio2"
|
||||
name="radios"
|
||||
value="option2"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio2">
|
||||
Blink
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
</CForm>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<div hidden={!hadSuccess && !hadFailure}>
|
||||
<div>
|
||||
<pre className="ignore">{responseBody}</pre>
|
||||
</div>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
Cancel
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</div>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<div hidden={!checkingIfSure}>Are you sure?</div>
|
||||
<CButton
|
||||
disabled={waiting}
|
||||
hidden={checkingIfSure}
|
||||
color="primary"
|
||||
onClick={() => confirmingIfSure()}
|
||||
>
|
||||
Schedule
|
||||
</CButton>
|
||||
<CButton
|
||||
hidden={!checkingIfSure}
|
||||
disabled={waiting}
|
||||
color="primary"
|
||||
onClick={() => doAction(false)}
|
||||
>
|
||||
{waiting && !doingNow ? 'Loading...' : 'Yes'} {' '}
|
||||
<CSpinner hidden={!waiting || doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
Cancel
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
)}
|
||||
</CModal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,161 +1,166 @@
|
||||
import {
|
||||
CButton,
|
||||
CModal,
|
||||
CModalHeader,
|
||||
CModalTitle,
|
||||
CModalBody,
|
||||
CModalFooter,
|
||||
CSpinner,
|
||||
CCol,
|
||||
CRow,
|
||||
CForm,
|
||||
CTextarea,
|
||||
CInvalidFeedback
|
||||
} from '@coreui/react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from '../../utils/authHelper';
|
||||
import { checkIfJson } from '../../utils/helper';
|
||||
import axiosInstance from '../../utils/axiosInstance';
|
||||
import eventBus from '../../utils/EventBus';
|
||||
|
||||
const ConfigureModal = ({ show, toggleModal }) => {
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
const [hadFailure, setHadFailure] = useState(false);
|
||||
const [doingNow, setDoingNow] = useState(false);
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
const [newConfig, setNewConfig] = useState('');
|
||||
const [responseBody, setResponseBody] = useState('');
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const [errorJson, setErrorJson] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
CButton,
|
||||
CModal,
|
||||
CModalHeader,
|
||||
CModalTitle,
|
||||
CModalBody,
|
||||
CModalFooter,
|
||||
CSpinner,
|
||||
CCol,
|
||||
CRow,
|
||||
CForm,
|
||||
CTextarea,
|
||||
CInvalidFeedback,
|
||||
} from '@coreui/react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from '../../utils/authHelper';
|
||||
import { checkIfJson } from '../../utils/helper';
|
||||
import axiosInstance from '../../utils/axiosInstance';
|
||||
import eventBus from '../../utils/EventBus';
|
||||
import SuccessfulActionModalBody from '../../components/SuccessfulActionModalBody';
|
||||
|
||||
const confirmingIfSure = () => {
|
||||
if (checkIfJson(newConfig)){
|
||||
setCheckingIfSure(true);
|
||||
}
|
||||
else {
|
||||
setErrorJson(true);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setResponseBody('');
|
||||
setCheckingIfSure(false);
|
||||
setDoingNow(false);
|
||||
setNewConfig('');
|
||||
setErrorJson(false);
|
||||
}, [show]);
|
||||
const ConfigureModal = ({ show, toggleModal }) => {
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
const [hadFailure, setHadFailure] = useState(false);
|
||||
const [doingNow, setDoingNow] = useState(false);
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
const [newConfig, setNewConfig] = useState('');
|
||||
const [responseBody, setResponseBody] = useState('');
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const [errorJson, setErrorJson] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
useEffect(() => {
|
||||
setErrorJson(false);
|
||||
}, [newConfig]);
|
||||
|
||||
const doAction = (isNow) => {
|
||||
setDoingNow(isNow);
|
||||
setHadFailure(false);
|
||||
setHadSuccess(false);
|
||||
setWaiting(true);
|
||||
|
||||
const token = getToken();
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
when: 0,
|
||||
UUID: 1,
|
||||
configuration: JSON.parse(newConfig),
|
||||
};
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/configure`, parameters, { headers })
|
||||
.then(() => {
|
||||
setResponseBody('Command submitted!');
|
||||
setHadSuccess(true);
|
||||
})
|
||||
.catch(() => {
|
||||
setResponseBody('Error while submitting command!');
|
||||
setHadFailure(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setDoingNow(false);
|
||||
setCheckingIfSure(false);
|
||||
setWaiting(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
});
|
||||
const confirmingIfSure = () => {
|
||||
if (checkIfJson(newConfig)) {
|
||||
setCheckingIfSure(true);
|
||||
} else {
|
||||
setErrorJson(true);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setResponseBody('');
|
||||
setCheckingIfSure(false);
|
||||
setDoingNow(false);
|
||||
setNewConfig('');
|
||||
setErrorJson(false);
|
||||
}, [show]);
|
||||
|
||||
useEffect(() => {
|
||||
setErrorJson(false);
|
||||
}, [newConfig]);
|
||||
|
||||
const doAction = (isNow) => {
|
||||
setDoingNow(isNow);
|
||||
setHadFailure(false);
|
||||
setHadSuccess(false);
|
||||
setWaiting(true);
|
||||
|
||||
const token = getToken();
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
when: 0,
|
||||
UUID: 1,
|
||||
configuration: JSON.parse(newConfig),
|
||||
};
|
||||
|
||||
return (
|
||||
<CModal show={show} onClose={toggleModal}>
|
||||
<CModalHeader closeButton>
|
||||
<CModalTitle>Configure Device</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CModalBody>
|
||||
<h6>Enter new device configuration: </h6>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol>
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/configure`, parameters, { headers })
|
||||
.then(() => {
|
||||
setResponseBody('Command submitted!');
|
||||
setHadSuccess(true);
|
||||
})
|
||||
.catch(() => {
|
||||
setResponseBody('Error while submitting command!');
|
||||
setHadFailure(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setDoingNow(false);
|
||||
setCheckingIfSure(false);
|
||||
setWaiting(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<CModal show={show} onClose={toggleModal}>
|
||||
<CModalHeader closeButton>
|
||||
<CModalTitle>Configure Device</CModalTitle>
|
||||
</CModalHeader>
|
||||
{hadSuccess ? (
|
||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||
) : (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>Enter new device configuration: </h6>
|
||||
<CRow style={{ marginTop: '20px' }}>
|
||||
<CCol>
|
||||
<CForm>
|
||||
<CTextarea
|
||||
name="textarea-input"
|
||||
id="textarea-input"
|
||||
rows="9"
|
||||
placeholder="Config JSON"
|
||||
value={newConfig}
|
||||
onChange={(event) => setNewConfig(event.target.value)}
|
||||
invalid={errorJson}
|
||||
/>
|
||||
<CInvalidFeedback className="help-block">
|
||||
You need to enter valid JSON
|
||||
</CInvalidFeedback>
|
||||
<CTextarea
|
||||
name="textarea-input"
|
||||
id="textarea-input"
|
||||
rows="9"
|
||||
placeholder="Config JSON"
|
||||
value={newConfig}
|
||||
onChange={(event) => setNewConfig(event.target.value)}
|
||||
invalid={errorJson}
|
||||
/>
|
||||
<CInvalidFeedback className="help-block">
|
||||
You need to enter valid JSON
|
||||
</CInvalidFeedback>
|
||||
</CForm>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<div hidden={!hadSuccess && !hadFailure}>
|
||||
<div>
|
||||
<pre className="ignore">{responseBody}</pre>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<div hidden={!hadSuccess && !hadFailure}>
|
||||
<div>
|
||||
<pre className="ignore">{responseBody}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<div hidden={!checkingIfSure}>Are you sure?</div>
|
||||
<CButton
|
||||
disabled={waiting}
|
||||
hidden={checkingIfSure}
|
||||
color="primary"
|
||||
onClick={() => confirmingIfSure()}
|
||||
>
|
||||
Submit
|
||||
</CButton>
|
||||
<CButton
|
||||
hidden={!checkingIfSure}
|
||||
disabled={waiting}
|
||||
color="primary"
|
||||
onClick={() => doAction(false)}
|
||||
>
|
||||
{waiting && !doingNow ? 'Loading...' : 'Yes'} {' '}
|
||||
<CSpinner hidden={!waiting || doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
Cancel
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</CModal>
|
||||
);
|
||||
};
|
||||
|
||||
ConfigureModal.propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
toggleModal: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ConfigureModal;
|
||||
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<div hidden={!checkingIfSure}>Are you sure?</div>
|
||||
<CButton
|
||||
disabled={waiting}
|
||||
hidden={checkingIfSure}
|
||||
color="primary"
|
||||
onClick={() => confirmingIfSure()}
|
||||
>
|
||||
Submit
|
||||
</CButton>
|
||||
<CButton
|
||||
hidden={!checkingIfSure}
|
||||
disabled={waiting}
|
||||
color="primary"
|
||||
onClick={() => doAction(false)}
|
||||
>
|
||||
{waiting && !doingNow ? 'Loading...' : 'Yes'} {' '}
|
||||
<CSpinner hidden={!waiting || doingNow} component="span" size="sm" />
|
||||
</CButton>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
Cancel
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</div>
|
||||
)}
|
||||
</CModal>
|
||||
);
|
||||
};
|
||||
|
||||
ConfigureModal.propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
toggleModal: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ConfigureModal;
|
||||
|
||||
@@ -117,7 +117,7 @@ const DeviceActions = ({ selectedDeviceId }) => {
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CButton block color="primary" onClick={toggleConfigModal}>
|
||||
Configure
|
||||
Configure
|
||||
</CButton>
|
||||
</CCol>
|
||||
</CRow>
|
||||
|
||||
@@ -58,7 +58,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
|
||||
const showMoreCommands = () => {
|
||||
setCommandLimit(commandLimit + 50);
|
||||
}
|
||||
};
|
||||
|
||||
const modifyStart = (value) => {
|
||||
setStart(value);
|
||||
@@ -86,17 +86,17 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
limit: commandLimit
|
||||
limit: commandLimit,
|
||||
},
|
||||
};
|
||||
|
||||
let extraParams = '&newest=true';
|
||||
if(start !=='' && end !==''){
|
||||
if (start !== '' && end !== '') {
|
||||
const utcStart = new Date(start).toISOString();
|
||||
const utcEnd = new Date(end).toISOString();
|
||||
options.params.startDate = dateToUnix(utcStart);
|
||||
options.params.endDate = dateToUnix(utcEnd);
|
||||
extraParams='';
|
||||
extraParams = '';
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
@@ -204,8 +204,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId && start !== '' && end !== '') {
|
||||
getCommands();
|
||||
}
|
||||
else if(selectedDeviceId && start === '' && end === ''){
|
||||
} else if (selectedDeviceId && start === '' && end === '') {
|
||||
getCommands();
|
||||
}
|
||||
}, [selectedDeviceId, start, end]);
|
||||
@@ -238,8 +237,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
useEffect(() => {
|
||||
if (commands.length === 0 || (commands.length > 0 && commands.length < commandLimit)) {
|
||||
setShowLoadingMore(false);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setShowLoadingMore(true);
|
||||
}
|
||||
}, [commands]);
|
||||
@@ -270,17 +268,11 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
<CRow style={{ marginBottom: '10px' }}>
|
||||
<CCol>
|
||||
From:
|
||||
<DatePicker
|
||||
includeTime
|
||||
onChange={(date) => modifyStart(date)}
|
||||
/>
|
||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
||||
</CCol>
|
||||
<CCol>
|
||||
To:
|
||||
<DatePicker
|
||||
includeTime
|
||||
onChange={(date) => modifyEnd(date)}
|
||||
/>
|
||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CCard>
|
||||
@@ -384,16 +376,16 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<CRow style={{marginBottom: '1%', marginRight: '1%'}}>
|
||||
{showLoadingMore &&
|
||||
<LoadingButton
|
||||
label="View More"
|
||||
isLoadingLabel="Loading More..."
|
||||
isLoading={loadingMore}
|
||||
action={showMoreCommands}
|
||||
variant="outline"
|
||||
/>
|
||||
}
|
||||
<CRow style={{ marginBottom: '1%', marginRight: '1%' }}>
|
||||
{showLoadingMore && (
|
||||
<LoadingButton
|
||||
label="View More"
|
||||
isLoadingLabel="Loading More..."
|
||||
isLoading={loadingMore}
|
||||
action={showMoreCommands}
|
||||
variant="outline"
|
||||
/>
|
||||
)}
|
||||
</CRow>
|
||||
</div>
|
||||
</CCard>
|
||||
|
||||
@@ -144,12 +144,12 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
|
||||
</CFormGroup>
|
||||
</CCollapse>
|
||||
<CCardFooter>
|
||||
<CButton
|
||||
show={collapse ? 'true' : 'false'}
|
||||
onClick={toggle}
|
||||
block
|
||||
>
|
||||
<CIcon style={{color: 'black'}} name={collapse ? 'cilChevronTop' : 'cilChevronBottom'} size="lg" />
|
||||
<CButton show={collapse ? 'true' : 'false'} onClick={toggle} block>
|
||||
<CIcon
|
||||
style={{ color: 'black' }}
|
||||
name={collapse ? 'cilChevronTop' : 'cilChevronBottom'}
|
||||
size="lg"
|
||||
/>
|
||||
</CButton>
|
||||
</CCardFooter>
|
||||
</CForm>
|
||||
|
||||
@@ -47,7 +47,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
|
||||
const showMoreLogs = () => {
|
||||
setLogLimit(logLimit + 50);
|
||||
}
|
||||
};
|
||||
|
||||
const getDeviceHealth = () => {
|
||||
if (loading) return;
|
||||
@@ -60,17 +60,17 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
limit: logLimit
|
||||
limit: logLimit,
|
||||
},
|
||||
};
|
||||
|
||||
let extraParams = '?newest=true';
|
||||
if(start !=='' && end !==''){
|
||||
if (start !== '' && end !== '') {
|
||||
const utcStart = new Date(start).toISOString();
|
||||
const utcEnd = new Date(end).toISOString();
|
||||
options.params.startDate = dateToUnix(utcStart);
|
||||
options.params.endDate = dateToUnix(utcEnd);
|
||||
extraParams='';
|
||||
extraParams = '';
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
@@ -133,12 +133,11 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
getDeviceHealth();
|
||||
}
|
||||
}, [logLimit]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (healthChecks.length === 0 || (healthChecks.length > 0 && healthChecks.length < logLimit)) {
|
||||
setShowLoadingMore(false);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setShowLoadingMore(true);
|
||||
}
|
||||
}, [healthChecks]);
|
||||
@@ -146,8 +145,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId && start !== '' && end !== '') {
|
||||
getDeviceHealth();
|
||||
}
|
||||
else if(selectedDeviceId && start === '' && end === ''){
|
||||
} else if (selectedDeviceId && start === '' && end === '') {
|
||||
getDeviceHealth();
|
||||
}
|
||||
}, [start, end, selectedDeviceId]);
|
||||
@@ -176,17 +174,11 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
<CRow style={{ marginBottom: '10px' }}>
|
||||
<CCol>
|
||||
From:
|
||||
<DatePicker
|
||||
includeTime
|
||||
onChange={(date) => modifyStart(date)}
|
||||
/>
|
||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
||||
</CCol>
|
||||
<CCol>
|
||||
To:
|
||||
<DatePicker
|
||||
includeTime
|
||||
onChange={(date) => modifyEnd(date)}
|
||||
/>
|
||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CCard>
|
||||
@@ -231,16 +223,16 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<CRow style={{marginBottom: '1%', marginRight: '1%'}}>
|
||||
{showLoadingMore &&
|
||||
<LoadingButton
|
||||
label="View More"
|
||||
isLoadingLabel="Loading More..."
|
||||
isLoading={loadingMore}
|
||||
action={showMoreLogs}
|
||||
variant="outline"
|
||||
/>
|
||||
}
|
||||
<CRow style={{ marginBottom: '1%', marginRight: '1%' }}>
|
||||
{showLoadingMore && (
|
||||
<LoadingButton
|
||||
label="View More"
|
||||
isLoadingLabel="Loading More..."
|
||||
isLoading={loadingMore}
|
||||
action={showMoreLogs}
|
||||
variant="outline"
|
||||
/>
|
||||
)}
|
||||
</CRow>
|
||||
</div>
|
||||
</CCard>
|
||||
|
||||
@@ -44,7 +44,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
|
||||
const showMoreLogs = () => {
|
||||
setLogLimit(logLimit + 50);
|
||||
}
|
||||
};
|
||||
|
||||
const getLogs = () => {
|
||||
if (loading) return;
|
||||
@@ -57,17 +57,17 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
limit: logLimit
|
||||
limit: logLimit,
|
||||
},
|
||||
};
|
||||
|
||||
let extraParams = '?newest=true';
|
||||
if(start !=='' && end !==''){
|
||||
if (start !== '' && end !== '') {
|
||||
const utcStart = new Date(start).toISOString();
|
||||
const utcEnd = new Date(end).toISOString();
|
||||
options.params.startDate = dateToUnix(utcStart);
|
||||
options.params.endDate = dateToUnix(utcEnd);
|
||||
extraParams='';
|
||||
extraParams = '';
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
@@ -133,8 +133,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
useEffect(() => {
|
||||
if (logs.length === 0 || (logs.length > 0 && logs.length < logLimit)) {
|
||||
setShowLoadingMore(false);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setShowLoadingMore(true);
|
||||
}
|
||||
}, [logs]);
|
||||
@@ -142,8 +141,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId && start !== '' && end !== '') {
|
||||
getLogs();
|
||||
}
|
||||
else if(selectedDeviceId && start === '' && end === ''){
|
||||
} else if (selectedDeviceId && start === '' && end === '') {
|
||||
getLogs();
|
||||
}
|
||||
}, [start, end, selectedDeviceId]);
|
||||
@@ -159,17 +157,11 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
<CRow style={{ marginBottom: '10px' }}>
|
||||
<CCol>
|
||||
From:
|
||||
<DatePicker
|
||||
includeTime
|
||||
onChange={(date) => modifyStart(date)}
|
||||
/>
|
||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
||||
</CCol>
|
||||
<CCol>
|
||||
To:
|
||||
<DatePicker
|
||||
includeTime
|
||||
onChange={(date) => modifyEnd(date)}
|
||||
/>
|
||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CCard>
|
||||
@@ -208,16 +200,16 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<CRow style={{marginBottom: '1%', marginRight: '1%'}}>
|
||||
{showLoadingMore &&
|
||||
<LoadingButton
|
||||
label="View More"
|
||||
isLoadingLabel="Loading More..."
|
||||
isLoading={loadingMore}
|
||||
action={showMoreLogs}
|
||||
variant="outline"
|
||||
/>
|
||||
}
|
||||
<CRow style={{ marginBottom: '1%', marginRight: '1%' }}>
|
||||
{showLoadingMore && (
|
||||
<LoadingButton
|
||||
label="View More"
|
||||
isLoadingLabel="Loading More..."
|
||||
isLoading={loadingMore}
|
||||
action={showMoreLogs}
|
||||
variant="outline"
|
||||
/>
|
||||
)}
|
||||
</CRow>
|
||||
</div>
|
||||
</CCard>
|
||||
|
||||
@@ -16,7 +16,8 @@ const DevicePage = () => {
|
||||
const previouslySelectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
useEffect(() => {
|
||||
if (deviceId && deviceId !== previouslySelectedDeviceId) dispatch({ type: 'set', selectedDeviceId: deviceId });
|
||||
if (deviceId && deviceId !== previouslySelectedDeviceId)
|
||||
dispatch({ type: 'set', selectedDeviceId: deviceId });
|
||||
}, [deviceId]);
|
||||
|
||||
return (
|
||||
@@ -34,7 +35,7 @@ const DevicePage = () => {
|
||||
</CRow>
|
||||
<CRow>
|
||||
<CCol>
|
||||
<DeviceStatisticsCard selectedDeviceId={deviceId} />
|
||||
<DeviceStatisticsCard selectedDeviceId={deviceId} />
|
||||
<DeviceCommands selectedDeviceId={deviceId} />
|
||||
</CCol>
|
||||
</CRow>
|
||||
|
||||
@@ -6,85 +6,83 @@ import { getToken } from '../../../utils/authHelper';
|
||||
import { addDays, dateToUnix } from '../../../utils/helper';
|
||||
|
||||
const DeviceLifetimeStatistics = ({ selectedDeviceId }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const displayInformation = (data) => {
|
||||
const sortedData = data.sort((a,b) => {
|
||||
if(a.recorded > b.recorded) return 1;
|
||||
if(b.recorded > a.recorded) return -1;
|
||||
return 0;
|
||||
});
|
||||
const interfaces = [
|
||||
{
|
||||
label: 'wan',
|
||||
backgroundColor: 'rgb(228,102,81,0.9)',
|
||||
data: [],
|
||||
fill: false
|
||||
},
|
||||
{
|
||||
label: 'lan',
|
||||
backgroundColor: 'rgb(0,216,255,0.9)',
|
||||
data: [],
|
||||
fill: false
|
||||
}
|
||||
];
|
||||
const displayInformation = (data) => {
|
||||
const sortedData = data.sort((a, b) => {
|
||||
if (a.recorded > b.recorded) return 1;
|
||||
if (b.recorded > a.recorded) return -1;
|
||||
return 0;
|
||||
});
|
||||
const interfaces = [
|
||||
{
|
||||
label: 'wan',
|
||||
backgroundColor: 'rgb(228,102,81,0.9)',
|
||||
data: [],
|
||||
fill: false,
|
||||
},
|
||||
{
|
||||
label: 'lan',
|
||||
backgroundColor: 'rgb(0,216,255,0.9)',
|
||||
data: [],
|
||||
fill: false,
|
||||
},
|
||||
];
|
||||
|
||||
const interfaceIndexes = {
|
||||
'wan': 0,
|
||||
'lan': 1
|
||||
};
|
||||
|
||||
for (const log of sortedData){
|
||||
for (const inter of log.data.interfaces){
|
||||
interfaces[interfaceIndexes[inter.name]].data.push(inter.counters.tx_bytes);
|
||||
}
|
||||
}
|
||||
setDataset(interfaces);
|
||||
}
|
||||
|
||||
const getStatistics = () => {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
serialNumber: "24f5a207a130",
|
||||
lifetime: true
|
||||
}
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${selectedDeviceId}/statistics`, options)
|
||||
.then((response) => {
|
||||
displayInformation(response.data.data);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
const interfaceIndexes = {
|
||||
wan: 0,
|
||||
lan: 1,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
getStatistics();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
for (const log of sortedData) {
|
||||
for (const inter of log.data.interfaces) {
|
||||
interfaces[interfaceIndexes[inter.name]].data.push(inter.counters.tx_bytes);
|
||||
}
|
||||
}
|
||||
setDataset(interfaces);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CChartLine
|
||||
datasets={dataset}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const getStatistics = () => {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
|
||||
DeviceLifetimeStatistics.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
serialNumber: '24f5a207a130',
|
||||
lifetime: true,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${selectedDeviceId}/statistics`, options)
|
||||
.then((response) => {
|
||||
displayInformation(response.data.data);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
getStatistics();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CChartLine datasets={dataset} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeviceLifetimeStatistics;
|
||||
DeviceLifetimeStatistics.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceLifetimeStatistics;
|
||||
|
||||
@@ -1,53 +1,44 @@
|
||||
import React, {useState} from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
CCard,
|
||||
CCardHeader,
|
||||
CCardBody,
|
||||
CPopover,
|
||||
CRow,
|
||||
CCol
|
||||
} from '@coreui/react';
|
||||
import { CCard, CCardHeader, CCardBody, CPopover, CRow, CCol } from '@coreui/react';
|
||||
import { cilSync } from '@coreui/icons';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import StatisticsChartList from './StatisticsChartList';
|
||||
|
||||
const DeviceStatisticsCard = ({ selectedDeviceId }) => {
|
||||
const [lastRefresh, setLastRefresh] = useState('');
|
||||
const [lastRefresh, setLastRefresh] = useState('');
|
||||
|
||||
const refresh = () => {
|
||||
setLastRefresh(new Date().toString());
|
||||
}
|
||||
const refresh = () => {
|
||||
setLastRefresh(new Date().toString());
|
||||
};
|
||||
|
||||
return (
|
||||
<CCard>
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol>
|
||||
Statistics
|
||||
</CCol>
|
||||
<CCol style={{textAlign: 'right'}}>
|
||||
<CPopover content="Refresh">
|
||||
<CIcon
|
||||
onClick={() => refresh()}
|
||||
name="cil-sync"
|
||||
content={cilSync}
|
||||
size="lg"
|
||||
color='primary'
|
||||
/>
|
||||
</CPopover>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
<CCardBody style={{padding: '5%'}}>
|
||||
<StatisticsChartList selectedDeviceId={selectedDeviceId} lastRefresh={lastRefresh}/>
|
||||
</CCardBody>
|
||||
</CCard>
|
||||
);
|
||||
return (
|
||||
<CCard>
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol>Statistics</CCol>
|
||||
<CCol style={{ textAlign: 'right' }}>
|
||||
<CPopover content="Refresh">
|
||||
<CIcon
|
||||
onClick={() => refresh()}
|
||||
name="cil-sync"
|
||||
content={cilSync}
|
||||
size="lg"
|
||||
color="primary"
|
||||
/>
|
||||
</CPopover>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
<CCardBody style={{ padding: '5%' }}>
|
||||
<StatisticsChartList selectedDeviceId={selectedDeviceId} lastRefresh={lastRefresh} />
|
||||
</CCardBody>
|
||||
</CCard>
|
||||
);
|
||||
};
|
||||
|
||||
DeviceStatisticsCard.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceStatisticsCard;
|
||||
export default DeviceStatisticsCard;
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Chart from 'react-apexcharts'
|
||||
import Chart from 'react-apexcharts';
|
||||
|
||||
const DeviceStatisticsChart = ({ data, options }) => (
|
||||
<div style={{height: '360px'}}>
|
||||
<Chart
|
||||
series={data}
|
||||
options={options}
|
||||
type='line'
|
||||
height='100%'
|
||||
/>
|
||||
</div>
|
||||
<div style={{ height: '360px' }}>
|
||||
<Chart series={data} options={options} type="line" height="100%" />
|
||||
</div>
|
||||
);
|
||||
|
||||
DeviceStatisticsChart.propTypes = {
|
||||
data: PropTypes.instanceOf(Array),
|
||||
options: PropTypes.instanceOf(Object),
|
||||
data: PropTypes.instanceOf(Array),
|
||||
options: PropTypes.instanceOf(Object),
|
||||
};
|
||||
|
||||
DeviceStatisticsChart.defaultProps = {
|
||||
data: [],
|
||||
options: {},
|
||||
data: [],
|
||||
options: {},
|
||||
};
|
||||
|
||||
export default DeviceStatisticsChart;
|
||||
export default DeviceStatisticsChart;
|
||||
|
||||
@@ -7,167 +7,167 @@ import { getToken } from '../../../utils/authHelper';
|
||||
import { unixToTime, capitalizeFirstLetter } from '../../../utils/helper';
|
||||
|
||||
const StatisticsChartList = ({ selectedDeviceId, lastRefresh }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [deviceStats, setStats] = useState([]);
|
||||
const [statOptions, setStatOptions] = useState({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [deviceStats, setStats] = useState([]);
|
||||
const [statOptions, setStatOptions] = useState({});
|
||||
|
||||
const transformIntoDataset = (data) => {
|
||||
const sortedData = data.sort((a,b) => {
|
||||
if(a.recorded > b.recorded) return 1;
|
||||
if(b.recorded > a.recorded) return -1;
|
||||
return 0;
|
||||
});
|
||||
const transformIntoDataset = (data) => {
|
||||
const sortedData = data.sort((a, b) => {
|
||||
if (a.recorded > b.recorded) return 1;
|
||||
if (b.recorded > a.recorded) return -1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// This dictionary will have a key that is the interface name and a value of it's index in the final array
|
||||
const interfaceTypes = {}
|
||||
const interfaceList = [];
|
||||
const categories = [];
|
||||
let i = 0;
|
||||
// This dictionary will have a key that is the interface name and a value of it's index in the final array
|
||||
const interfaceTypes = {};
|
||||
const interfaceList = [];
|
||||
const categories = [];
|
||||
let i = 0;
|
||||
|
||||
// Just building the array for all the interfaces
|
||||
for (const log of sortedData){
|
||||
categories.push(unixToTime(log.recorded));
|
||||
for (const logInterface of log.data.interfaces){
|
||||
if(interfaceTypes[logInterface.name] === undefined) {
|
||||
interfaceTypes[logInterface.name] = i;
|
||||
interfaceList.push([{
|
||||
titleName: logInterface.name,
|
||||
name: 'Tx',
|
||||
backgroundColor: 'rgb(228,102,81,0.9)',
|
||||
data: [],
|
||||
fill: false
|
||||
},
|
||||
{
|
||||
titleName: logInterface.name,
|
||||
name: 'Rx',
|
||||
backgroundColor: 'rgb(0,216,255,0.9)',
|
||||
data: [],
|
||||
fill: false
|
||||
}]);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
// Just building the array for all the interfaces
|
||||
for (const log of sortedData) {
|
||||
categories.push(unixToTime(log.recorded));
|
||||
for (const logInterface of log.data.interfaces) {
|
||||
if (interfaceTypes[logInterface.name] === undefined) {
|
||||
interfaceTypes[logInterface.name] = i;
|
||||
interfaceList.push([
|
||||
{
|
||||
titleName: logInterface.name,
|
||||
name: 'Tx',
|
||||
backgroundColor: 'rgb(228,102,81,0.9)',
|
||||
data: [],
|
||||
fill: false,
|
||||
},
|
||||
{
|
||||
titleName: logInterface.name,
|
||||
name: 'Rx',
|
||||
backgroundColor: 'rgb(0,216,255,0.9)',
|
||||
data: [],
|
||||
fill: false,
|
||||
},
|
||||
]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Looping through all the data
|
||||
for (const log of sortedData){
|
||||
// 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));
|
||||
interfaceList[interfaceTypes[inter.name]][1].data.push(Math.floor(inter.counters.rx_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
chart: {
|
||||
id: 'chart',
|
||||
group: 'txrx'
|
||||
},
|
||||
xaxis: {
|
||||
title: {
|
||||
text: 'Time',
|
||||
style: {
|
||||
fontSize: '15px'
|
||||
},
|
||||
},
|
||||
categories,
|
||||
tickAmount:20
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
minWidth: 40
|
||||
},
|
||||
title: {
|
||||
text: 'Data (KB)',
|
||||
style: {
|
||||
fontSize: '15px'
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: 'top',
|
||||
horizontalAlign: 'right',
|
||||
float: true
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
setStatOptions(options);
|
||||
setStats(interfaceList);
|
||||
}
|
||||
}
|
||||
|
||||
const getStatistics = () => {
|
||||
if (!loading){
|
||||
setLoading(true);
|
||||
// Looping through all the data
|
||||
for (const log of sortedData) {
|
||||
// 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),
|
||||
);
|
||||
interfaceList[interfaceTypes[inter.name]][1].data.push(Math.floor(inter.counters.rx_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
serialNumber: "24f5a207a130"
|
||||
}
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${selectedDeviceId}/statistics?newest=true&limit=50`, options)
|
||||
.then((response) => {
|
||||
transformIntoDataset(response.data.data);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
const options = {
|
||||
chart: {
|
||||
id: 'chart',
|
||||
group: 'txrx',
|
||||
},
|
||||
xaxis: {
|
||||
title: {
|
||||
text: 'Time',
|
||||
style: {
|
||||
fontSize: '15px',
|
||||
},
|
||||
},
|
||||
categories,
|
||||
tickAmount: 20,
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
minWidth: 40,
|
||||
},
|
||||
title: {
|
||||
text: 'Data (KB)',
|
||||
style: {
|
||||
fontSize: '15px',
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: 'top',
|
||||
horizontalAlign: 'right',
|
||||
float: true,
|
||||
},
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
getStatistics();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
setStatOptions(options);
|
||||
setStats(interfaceList);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (lastRefresh !== '' && selectedDeviceId){
|
||||
getStatistics();
|
||||
}
|
||||
}, [lastRefresh])
|
||||
const getStatistics = () => {
|
||||
if (!loading) {
|
||||
setLoading(true);
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
serialNumber: '24f5a207a130',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
deviceStats.map(
|
||||
(data) =>
|
||||
<div key={createUuid()}>
|
||||
<DeviceStatisticsChart
|
||||
key={createUuid()}
|
||||
data={data}
|
||||
options={{
|
||||
...statOptions,
|
||||
title: {
|
||||
text: capitalizeFirstLetter(data[0].titleName),
|
||||
align: 'left',
|
||||
style: {
|
||||
fontSize: '25px'
|
||||
},
|
||||
}
|
||||
}} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
axiosInstance
|
||||
.get(`/device/${selectedDeviceId}/statistics?newest=true&limit=50`, options)
|
||||
.then((response) => {
|
||||
transformIntoDataset(response.data.data);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
getStatistics();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (lastRefresh !== '' && selectedDeviceId) {
|
||||
getStatistics();
|
||||
}
|
||||
}, [lastRefresh]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{deviceStats.map((data) => (
|
||||
<div key={createUuid()}>
|
||||
<DeviceStatisticsChart
|
||||
key={createUuid()}
|
||||
data={data}
|
||||
options={{
|
||||
...statOptions,
|
||||
title: {
|
||||
text: capitalizeFirstLetter(data[0].titleName),
|
||||
align: 'left',
|
||||
style: {
|
||||
fontSize: '25px',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
StatisticsChartList.propTypes = {
|
||||
lastRefresh: PropTypes.string,
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
lastRefresh: PropTypes.string,
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
StatisticsChartList.defaultProps = {
|
||||
lastRefresh: ''
|
||||
}
|
||||
lastRefresh: '',
|
||||
};
|
||||
|
||||
export default StatisticsChartList;
|
||||
export default StatisticsChartList;
|
||||
|
||||
@@ -5,8 +5,6 @@ import {
|
||||
CModalTitle,
|
||||
CModalBody,
|
||||
CModalFooter,
|
||||
CSpinner,
|
||||
CBadge,
|
||||
CCol,
|
||||
CRow,
|
||||
CInvalidFeedback,
|
||||
@@ -21,6 +19,7 @@ import 'react-widgets/styles.css';
|
||||
import { getToken } from '../../utils/authHelper';
|
||||
import axiosInstance from '../../utils/axiosInstance';
|
||||
import eventBus from '../../utils/EventBus';
|
||||
import LoadingButton from '../../components/LoadingButton';
|
||||
|
||||
const TraceModal = ({ show, toggleModal }) => {
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
@@ -31,7 +30,6 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
const [packets, setPackets] = useState(100);
|
||||
const [chosenDate, setChosenDate] = useState(new Date().toString());
|
||||
const [responseBody, setResponseBody] = useState('');
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const setDate = (date) => {
|
||||
@@ -40,17 +38,12 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const confirmingIfSure = () => {
|
||||
setCheckingIfSure(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setChosenDate(new Date().toString());
|
||||
setResponseBody('');
|
||||
setCheckingIfSure(false);
|
||||
setDuration(20);
|
||||
setPackets(100);
|
||||
}, [show]);
|
||||
@@ -99,7 +92,6 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
setHadFailure(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setCheckingIfSure(false);
|
||||
setWaiting(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
});
|
||||
@@ -199,25 +191,15 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
</div>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<div hidden={!checkingIfSure}>Are you sure?</div>
|
||||
<CButton hidden={checkingIfSure} color="primary" onClick={() => confirmingIfSure()}>
|
||||
Schedule
|
||||
</CButton>
|
||||
<CButton
|
||||
hidden={!checkingIfSure}
|
||||
<LoadingButton
|
||||
label="Schedule"
|
||||
isLoadingLabel="Loading..."
|
||||
isLoading={waiting}
|
||||
action={doAction}
|
||||
variant="outline"
|
||||
block={false}
|
||||
disabled={waiting}
|
||||
color="primary"
|
||||
onClick={() => doAction()}
|
||||
>
|
||||
{waiting ? 'Loading...' : 'Yes'} {' '}
|
||||
<CSpinner hidden={!waiting} component="span" size="sm" />
|
||||
<CBadge hidden={waiting || !hadSuccess} color="success" shape="pill">
|
||||
Success
|
||||
</CBadge>
|
||||
<CBadge hidden={waiting || !hadFailure} color="danger" shape="pill">
|
||||
Request Failed
|
||||
</CBadge>
|
||||
</CButton>
|
||||
/>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
Cancel
|
||||
</CButton>
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
CModalTitle,
|
||||
CModalBody,
|
||||
CModalFooter,
|
||||
CSpinner,
|
||||
CRow,
|
||||
CForm,
|
||||
CSwitch,
|
||||
@@ -18,6 +17,7 @@ import 'react-widgets/styles.css';
|
||||
import { getToken } from '../../utils/authHelper';
|
||||
import axiosInstance from '../../utils/axiosInstance';
|
||||
import eventBus from '../../utils/EventBus';
|
||||
import LoadingButton from '../../components/LoadingButton';
|
||||
|
||||
const WifiScanModal = ({ show, toggleModal }) => {
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
@@ -25,23 +25,17 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
const [choseVerbose, setVerbose] = useState(true);
|
||||
const [channelList, setChannelList] = useState([]);
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleVerbose = () => {
|
||||
setVerbose(!choseVerbose);
|
||||
};
|
||||
|
||||
const confirmingIfSure = () => {
|
||||
setCheckingIfSure(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setHadSuccess(false);
|
||||
setHadFailure(false);
|
||||
setWaiting(false);
|
||||
setChannelList([]);
|
||||
setCheckingIfSure(false);
|
||||
setVerbose(true);
|
||||
}, [show]);
|
||||
|
||||
@@ -108,7 +102,6 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
||||
setHadFailure(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setCheckingIfSure(false);
|
||||
setWaiting(false);
|
||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
||||
});
|
||||
@@ -138,19 +131,15 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
||||
</div>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<div hidden={!checkingIfSure}>Are you sure?</div>
|
||||
<CButton hidden={checkingIfSure} color="primary" onClick={() => confirmingIfSure()}>
|
||||
{hadSuccess || hadFailure ? 'Re-Scan' : 'Scan'}
|
||||
</CButton>
|
||||
<CButton
|
||||
hidden={!checkingIfSure}
|
||||
<LoadingButton
|
||||
label="Schedule"
|
||||
isLoadingLabel="Loading..."
|
||||
isLoading={waiting}
|
||||
action={doAction}
|
||||
variant="outline"
|
||||
block={false}
|
||||
disabled={waiting}
|
||||
color="primary"
|
||||
onClick={() => doAction()}
|
||||
>
|
||||
{waiting ? 'Loading...' : 'Yes'} {' '}
|
||||
<CSpinner hidden={!waiting} component="span" size="sm" />
|
||||
</CButton>
|
||||
/>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
Cancel
|
||||
</CButton>
|
||||
|
||||
@@ -38,24 +38,24 @@ const Login = () => {
|
||||
const formValidation = () => {
|
||||
setHadError(false);
|
||||
|
||||
let isSuccesful = true;
|
||||
let isSuccessful = true;
|
||||
|
||||
if (userId.trim() === '') {
|
||||
setEmptyUsername(true);
|
||||
isSuccesful = false;
|
||||
isSuccessful = false;
|
||||
}
|
||||
|
||||
if (password.trim() === '') {
|
||||
setEmptyPassword(true);
|
||||
isSuccesful = false;
|
||||
isSuccessful = false;
|
||||
}
|
||||
|
||||
if (gatewayUrl.trim() === '') {
|
||||
setEmptyGateway(true);
|
||||
isSuccesful = false;
|
||||
isSuccessful = false;
|
||||
}
|
||||
|
||||
return isSuccesful;
|
||||
return isSuccessful;
|
||||
};
|
||||
|
||||
const SignIn = (credentials) => {
|
||||
|
||||
@@ -60,7 +60,7 @@ export const unixToTime = (dateString) => {
|
||||
return `${prettyNumber(date.getHours())}:${prettyNumber(date.getMinutes())}:${prettyNumber(
|
||||
date.getSeconds(),
|
||||
)}`;
|
||||
}
|
||||
};
|
||||
|
||||
export const dateToUnix = (date) => Math.floor(new Date(date).getTime() / 1000);
|
||||
|
||||
@@ -69,10 +69,8 @@ export const capitalizeFirstLetter = (string) => string.charAt(0).toUpperCase()
|
||||
export const checkIfJson = (string) => {
|
||||
try {
|
||||
JSON.parse(string);
|
||||
}
|
||||
catch (e) {
|
||||
return false
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user