(
-
+
@@ -125,14 +125,16 @@ const FirmwareList = ({
),
show_details: (item) => (
|
- toggleEditModal(item.id)}
- >
-
-
+
+ toggleEditModal(item.id)}
+ >
+
+
+
|
),
}}
diff --git a/src/components/FormattedDate/index.js b/src/components/FormattedDate/index.js
index a3ae1e3..321d8ad 100644
--- a/src/components/FormattedDate/index.js
+++ b/src/components/FormattedDate/index.js
@@ -4,7 +4,7 @@ import { CPopover } from '@coreui/react';
import { formatDaysAgo, prettyDate } from 'utils/formatting';
const FormattedDate = ({ date }) => (
-
+
{date === 0 ? '-' : formatDaysAgo(date)}
);
diff --git a/src/components/HideTextButton/index.js b/src/components/HideTextButton/index.js
index 0416983..fa2e0e4 100644
--- a/src/components/HideTextButton/index.js
+++ b/src/components/HideTextButton/index.js
@@ -5,7 +5,7 @@ import { CButton, CPopover } from '@coreui/react';
const HideTextButton = ({ t, toggle, show, size }) => (
-
+
diff --git a/src/components/InventoryTable/index.js b/src/components/InventoryTable/index.js
index 147df48..ec3de3a 100644
--- a/src/components/InventoryTable/index.js
+++ b/src/components/InventoryTable/index.js
@@ -203,7 +203,7 @@ const InventoryTable = ({
-
+
-
+
toggleEditModal(item.id)}
style={{ width: '33px', height: '30px' }}
>
-
+
diff --git a/src/components/SimulationTable/index.js b/src/components/SimulationTable/index.js
new file mode 100644
index 0000000..3c2dc88
--- /dev/null
+++ b/src/components/SimulationTable/index.js
@@ -0,0 +1,273 @@
+import React, { useEffect } from 'react';
+import PropTypes from 'prop-types';
+import ReactPaginate from 'react-paginate';
+import {
+ CCardBody,
+ CDataTable,
+ CButton,
+ CCard,
+ CCardHeader,
+ CRow,
+ CCol,
+ CPopover,
+ CSelect,
+ CButtonToolbar,
+ CButtonClose,
+} from '@coreui/react';
+import { cilTrash, cilSearch, cilMediaPlay } from '@coreui/icons';
+import CIcon from '@coreui/icons-react';
+import ReactTooltip from 'react-tooltip';
+import { v4 as createUuid } from 'uuid';
+import styles from './index.module.scss';
+
+const SimulationTable = ({
+ currentPage,
+ simulations,
+ simulationsPerPage,
+ loading,
+ updateSimulationsPerPage,
+ pageCount,
+ updatePage,
+ t,
+ deleteSimulation,
+ toggleEdit,
+ startSim,
+}) => {
+ const columns = [
+ { key: 'name', label: t('user.name'), filter: false, sorter: false, _style: { width: '10%' } },
+ {
+ key: 'gateway',
+ label: t('simulation.gateway'),
+ filter: false,
+ sorter: false,
+ _style: { width: '10%' },
+ },
+ { key: 'deviceType', label: t('firmware.device_type'), filter: false, sorter: false },
+ { key: 'devices', label: t('common.devices'), filter: false, sorter: false },
+ { key: 'macPrefix', label: t('simulation.mac_prefix'), filter: false, sorter: false },
+ { key: 'stateInterval', label: t('simulation.state_interval'), filter: false, sorter: false },
+ {
+ key: 'minAssociations',
+ label: t('simulation.min_associations'),
+ filter: false,
+ sorter: false,
+ },
+ {
+ key: 'maxAssociations',
+ label: t('simulation.max_associations'),
+ filter: false,
+ sorter: false,
+ },
+ { key: 'minClients', label: t('simulation.min_clients'), filter: false, sorter: false },
+ { key: 'maxClients', label: t('simulation.max_clients'), filter: false, sorter: false },
+ { key: 'simulationLength', label: t('simulation.length'), filter: false, sorter: false },
+ { key: 'actions', label: '', filter: false, sorter: false, _style: { width: '1%' } },
+ ];
+
+ const hideTooltips = () => ReactTooltip.hide();
+
+ const escFunction = (event) => {
+ if (event.keyCode === 27) {
+ hideTooltips();
+ }
+ };
+
+ useEffect(() => {
+ document.addEventListener('keydown', escFunction, false);
+
+ return () => {
+ document.removeEventListener('keydown', escFunction, false);
+ };
+ }, []);
+
+ const deleteButton = ({ name, id }) => {
+ const tooltipId = createUuid();
+
+ return (
+
+
+
+
+
+ {
+ const element = document.getElementById(tooltipId);
+ const tooltipWidth = element ? element.offsetWidth : 0;
+ const newLeft = left - tooltipWidth * 0.25;
+ return { top, left: newLeft };
+ }}
+ >
+
+ {t('simulation.delete_simulation', { name })}
+ {
+ e.target.parentNode.parentNode.classList.remove('show');
+ hideTooltips();
+ }}
+ />
+
+
+
+
+ deleteSimulation(id)}
+ block
+ >
+ {t('common.confirm')}
+
+
+
+
+
+
+
+ );
+ };
+
+ return (
+ <>
+
+
+ {item.name} | ,
+ gateway: (item) => {item.gateway} | ,
+ deviceType: (item) => {item.deviceType} | ,
+ devices: (item) => {item.devices} | ,
+ macPrefix: (item) => {item.macPrefix} | ,
+ healthCheckInterval: (item) => (
+ {item.healthCheckInterval} |
+ ),
+ stateInterval: (item) => {item.stateInterval} | ,
+ minAssociations: (item) => {item.minAssociations} | ,
+ maxAssociations: (item) => {item.maxAssociations} | ,
+ minClients: (item) => {item.minClients} | ,
+ maxClients: (item) => {item.maxClients} | ,
+ simulationLength: (item) => {item.simulationLength} | ,
+ actions: (item) => (
+
+
+
+ startSim(item.id)}
+ >
+
+
+
+ {deleteButton(item)}
+
+ toggleEdit(item.id)}
+ >
+
+
+
+
+ |
+ ),
+ }}
+ />
+
+
+
+
+ {t('common.items_per_page')}
+
+ updateSimulationsPerPage(e.target.value)}
+ disabled={loading}
+ >
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+SimulationTable.propTypes = {
+ startSim: PropTypes.func.isRequired,
+ currentPage: PropTypes.string,
+ simulations: PropTypes.instanceOf(Array).isRequired,
+ updateSimulationsPerPage: PropTypes.func.isRequired,
+ pageCount: PropTypes.number.isRequired,
+ updatePage: PropTypes.func.isRequired,
+ simulationsPerPage: PropTypes.string.isRequired,
+ t: PropTypes.func.isRequired,
+ loading: PropTypes.bool.isRequired,
+ toggleEdit: PropTypes.func.isRequired,
+ deleteSimulation: PropTypes.func.isRequired,
+};
+
+SimulationTable.defaultProps = {
+ currentPage: '0',
+};
+
+export default React.memo(SimulationTable);
diff --git a/src/components/SimulationTable/index.module.scss b/src/components/SimulationTable/index.module.scss
new file mode 100644
index 0000000..5e7facb
--- /dev/null
+++ b/src/components/SimulationTable/index.module.scss
@@ -0,0 +1,16 @@
+.deleteTooltip {
+ opacity: 1 !important;
+ padding: 0px 0px 0px 0px !important;
+ border-radius: 1rem !important;
+ background-color: #fff !important;
+ border-color: #321fdb !important;
+ font-size: 0.875rem !important;
+ font-weight: 400 !important;
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2) !important;
+ width: 300px;
+}
+
+.tooltipHeader {
+ border-top-left-radius: 1rem !important;
+ border-top-right-radius: 1rem !important;
+}
diff --git a/src/components/UserListTable/index.js b/src/components/UserListTable/index.js
index fedf762..9272e2f 100644
--- a/src/components/UserListTable/index.js
+++ b/src/components/UserListTable/index.js
@@ -169,6 +169,7 @@ const UserListTable = ({
onClick={() => handleDeleteClick(item.Id)}
color="primary"
variant="outline"
+ shape="square"
size="sm"
>
diff --git a/src/index.js b/src/index.js
index 3b35229..2ca1e8b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -14,6 +14,7 @@ export { default as AddEntityForm } from './components/AddEntityForm';
export { default as AddInventoryTagForm } from './components/AddInventoryTagForm';
export { default as AddLocationForm } from './components/AddLocationForm';
export { default as AddressEditor } from './components/AddressEditor';
+export { default as AddSimulationForm } from './components/AddSimulationForm';
export { default as ApiStatusCard } from './components/ApiStatusCard';
export { default as Avatar } from './components/Avatar';
export { default as CompactNotesTable } from './components/CompactNotesTable';
@@ -29,6 +30,7 @@ export { default as ConfigurationSelect } from './components/Configuration/Selec
export { default as ConfigurationStringField } from './components/Configuration/StringField';
export { default as ConfigurationToggle } from './components/Configuration/Toggle';
export { default as ConfirmFooter } from './components/ConfirmFooter';
+export { default as ConfirmStopEditingButton } from './components/ConfirmStopEditingButton';
export { default as ContactTable } from './components/ContactTable';
export { default as CopyToClipboardButton } from './components/CopyToClipboardButton';
export { default as CreateUserForm } from './components/CreateUserForm';
@@ -45,8 +47,10 @@ export { default as EditEntityForm } from './components/EditEntityForm';
export { default as EditInventoryTagForm } from './components/EditInventoryTagForm';
export { default as EditLocationForm } from './components/EditLocationForm';
export { default as EditMyProfile } from './components/EditMyProfile';
+export { default as EditSimulationForm } from './components/EditSimulationForm';
export { default as EditUserForm } from './components/EditUserForm';
export { default as EditUserModal } from './components/EditUserModal';
+export { default as EntityTree } from './components/EntityTree';
export { default as EventQueueModal } from './components/EventQueueModal';
export { default as InventoryTable } from './components/InventoryTable';
export { default as FileToStringButton } from './components/FileToStringButton';
@@ -62,6 +66,7 @@ export { default as LoadingButton } from './components/LoadingButton';
export { default as NetworkDiagram } from './components/NetworkDiagram';
export { default as NotesTable } from './components/NotesTable';
export { default as RadioAnalysisTable } from './components/RadioAnalysisTable';
+export { default as SimulationTable } from './components/SimulationTable';
export { default as UserListTable } from './components/UserListTable';
export { default as VenueTable } from './components/VenueTable';
export { default as WifiAnalysisTable } from './components/WifiAnalysisTable';
diff --git a/src/layout/Header/index.js b/src/layout/Header/index.js
index 2ba0ddf..cd664b2 100644
--- a/src/layout/Header/index.js
+++ b/src/layout/Header/index.js
@@ -30,6 +30,8 @@ const Header = ({
user,
avatar,
hideBreadcrumb,
+ extraButton,
+ hideSidebarButton,
}) => {
const [translatedRoutes, setTranslatedRoutes] = useState(routes);
@@ -49,14 +51,25 @@ const Header = ({
return (
-
-
+ {hideSidebarButton ? null : (
+ <>
+
+
+ >
+ )}
-
+
+ {extraButton}
+
@@ -78,12 +91,14 @@ const Header = ({
-
-
-
+ {hideBreadcrumb ? null : (
+
+
+
+ )}
);
};
@@ -101,10 +116,14 @@ Header.propTypes = {
user: PropTypes.instanceOf(Object).isRequired,
avatar: PropTypes.string.isRequired,
hideBreadcrumb: PropTypes.bool,
+ extraButton: PropTypes.node,
+ hideSidebarButton: PropTypes.bool,
};
Header.defaultProps = {
+ extraButton: null,
hideBreadcrumb: false,
+ hideSidebarButton: false,
};
export default React.memo(Header);
diff --git a/src/layout/Sidebar/index.js b/src/layout/Sidebar/index.js
index 4687900..f3fe95e 100644
--- a/src/layout/Sidebar/index.js
+++ b/src/layout/Sidebar/index.js
@@ -13,16 +13,26 @@ import {
import PropTypes from 'prop-types';
import styles from './index.module.scss';
-const Sidebar = ({ showSidebar, setShowSidebar, logo, options, redirectTo }) => (
+const Sidebar = ({
+ showSidebar,
+ setShowSidebar,
+ logo,
+ options,
+ redirectTo,
+ logoHeight,
+ logoWidth,
+}) => (
setShowSidebar(val)}>
@@ -48,6 +58,13 @@ Sidebar.propTypes = {
logo: PropTypes.string.isRequired,
options: PropTypes.arrayOf(Object).isRequired,
redirectTo: PropTypes.string.isRequired,
+ logoHeight: PropTypes.string,
+ logoWidth: PropTypes.string,
+};
+
+Sidebar.defaultProps = {
+ logoHeight: null,
+ logoWidth: null,
};
export default React.memo(Sidebar);
|