diff --git a/package-lock.json b/package-lock.json
index 60b4798..3e2147b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ucentral-libs",
- "version": "0.9.51",
+ "version": "0.9.71",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ucentral-libs",
- "version": "0.9.51",
+ "version": "0.9.71",
"license": "BSD-3-Clause",
"dependencies": {
"@coreui/coreui": "^3.4.0",
@@ -14,9 +14,11 @@
"@coreui/icons-react": "^1.1.0",
"@coreui/react": "^3.4.6",
"@coreui/react-chartjs": "^1.1.0",
+ "libphonenumber-js": "^1.9.37",
"lodash": "^4.17.21",
"react-flow-renderer": "^9.6.6",
"react-paginate": "^7.1.3",
+ "react-phone-input-2": "^2.14.0",
"react-router-dom": "^5.2.0",
"react-select": "^4.3.1",
"react-tooltip": "^4.2.21",
@@ -8278,6 +8280,11 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/libphonenumber-js": {
+ "version": "1.9.37",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.37.tgz",
+ "integrity": "sha512-RnUR4XwiVhMLnT7uFSdnmLeprspquuDtaShAgKTA+g/ms9/S4hQU3/QpFdh3iXPHtxD52QscXLm2W2+QBmvYAg=="
+ },
"node_modules/lines-and-columns": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
@@ -8518,8 +8525,12 @@
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
- "dev": true
+ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
+ },
+ "node_modules/lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@@ -8527,6 +8538,16 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "node_modules/lodash.reduce": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
+ "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
+ },
+ "node_modules/lodash.startswith": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz",
+ "integrity": "sha1-xZjErc4YiiflMUVzHNxsDnF3YAw="
+ },
"node_modules/lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -10482,6 +10503,23 @@
"react": "^16.0.0 || ^17.0.0"
}
},
+ "node_modules/react-phone-input-2": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/react-phone-input-2/-/react-phone-input-2-2.14.0.tgz",
+ "integrity": "sha512-gOY3jUpwO7ulryXPEdqzH7L6DPqI9RQxKfBxZbgqAwXyALGsmwLWFyi2RQwXlBLWN/EPPT4Nv6I9TESVY2YBcg==",
+ "dependencies": {
+ "classnames": "^2.2.6",
+ "lodash.debounce": "^4.0.8",
+ "lodash.memoize": "^4.1.2",
+ "lodash.reduce": "^4.6.0",
+ "lodash.startswith": "^4.2.1",
+ "prop-types": "^15.7.2"
+ },
+ "peerDependencies": {
+ "react": "^16.12.0 || ^17.0.0",
+ "react-dom": "^16.12.0 || ^17.0.0"
+ }
+ },
"node_modules/react-redux": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
@@ -20369,6 +20407,11 @@
"type-check": "~0.4.0"
}
},
+ "libphonenumber-js": {
+ "version": "1.9.37",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.37.tgz",
+ "integrity": "sha512-RnUR4XwiVhMLnT7uFSdnmLeprspquuDtaShAgKTA+g/ms9/S4hQU3/QpFdh3iXPHtxD52QscXLm2W2+QBmvYAg=="
+ },
"lines-and-columns": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
@@ -20557,8 +20600,12 @@
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
- "dev": true
+ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
+ },
+ "lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
},
"lodash.merge": {
"version": "4.6.2",
@@ -20566,6 +20613,16 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "lodash.reduce": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
+ "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
+ },
+ "lodash.startswith": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz",
+ "integrity": "sha1-xZjErc4YiiflMUVzHNxsDnF3YAw="
+ },
"lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -22049,6 +22106,19 @@
"prop-types": "^15.6.1"
}
},
+ "react-phone-input-2": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/react-phone-input-2/-/react-phone-input-2-2.14.0.tgz",
+ "integrity": "sha512-gOY3jUpwO7ulryXPEdqzH7L6DPqI9RQxKfBxZbgqAwXyALGsmwLWFyi2RQwXlBLWN/EPPT4Nv6I9TESVY2YBcg==",
+ "requires": {
+ "classnames": "^2.2.6",
+ "lodash.debounce": "^4.0.8",
+ "lodash.memoize": "^4.1.2",
+ "lodash.reduce": "^4.6.0",
+ "lodash.startswith": "^4.2.1",
+ "prop-types": "^15.7.2"
+ }
+ },
"react-redux": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
diff --git a/package.json b/package.json
index ffbd4c0..b0268a0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ucentral-libs",
- "version": "0.9.51",
+ "version": "0.9.71",
"main": "dist/index.js",
"source": "src/index.js",
"engines": {
@@ -9,20 +9,22 @@
"files": [
"dist"
],
- "license" : "BSD-3-Clause",
+ "license": "BSD-3-Clause",
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
"@coreui/icons-react": "^1.1.0",
"@coreui/react": "^3.4.6",
"@coreui/react-chartjs": "^1.1.0",
- "react-tooltip": "^4.2.21",
+ "libphonenumber-js": "^1.9.37",
+ "lodash": "^4.17.21",
"react-flow-renderer": "^9.6.6",
"react-paginate": "^7.1.3",
+ "react-phone-input-2": "^2.14.0",
"react-router-dom": "^5.2.0",
"react-select": "^4.3.1",
- "uuid": "^8.3.2",
- "lodash": "^4.17.21"
+ "react-tooltip": "^4.2.21",
+ "uuid": "^8.3.2"
},
"peerDependencies": {
"prop-types": "^15.7.2",
diff --git a/src/components/AddContactForm/index.js b/src/components/AddContactForm/index.js
new file mode 100644
index 0000000..53f809e
--- /dev/null
+++ b/src/components/AddContactForm/index.js
@@ -0,0 +1,353 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import Select from 'react-select';
+import CreatableSelect from 'react-select/creatable';
+import {
+ CForm,
+ CInput,
+ CLabel,
+ CCol,
+ CFormGroup,
+ CInvalidFeedback,
+ CFormText,
+ CRow,
+ CDataTable,
+ CLink,
+ CPopover,
+ CButton,
+} from '@coreui/react';
+import CIcon from '@coreui/icons-react';
+import { cilPlus } from '@coreui/icons';
+import FormattedDate from '../FormattedDate';
+
+const AddContactForm = ({ t, disable, fields, updateField, updateFieldWithKey, entities }) => {
+ const [filter, setFilter] = useState('');
+ const [selectedEntity, setSelectedEntity] = useState('');
+
+ const onPhonesChange = (v) => updateFieldWithKey('phones', { value: v.map((obj) => obj.value) });
+ const onMobilesChange = (v) =>
+ updateFieldWithKey('mobiles', { value: v.map((obj) => obj.value) });
+
+ const NoOptionsMessage = () => (
+
{t('common.type_for_options')}
+ );
+
+ const columns = [
+ { key: 'created', label: t('common.created'), _style: { width: '20%' }, filter: false },
+ { key: 'name', label: t('user.name'), _style: { width: '25%' }, filter: false },
+ { key: 'description', label: t('user.description'), _style: { width: '50%' } },
+ { key: 'actions', label: '', _style: { width: '15%' }, filter: false },
+ ];
+
+ const selectEntity = ({ id, name }) => {
+ updateFieldWithKey('entity', { value: id });
+ setSelectedEntity(name);
+ };
+
+ return (
+
+
+
+ {t('contact.type')}
+
+
+
+
+ {t('common.required')}
+
+
+ {t('contact.user_title')}
+
+
+
+
+
+ {t('contact.salutation')}
+
+
+
+
+
+
+ {t('contact.access_pin')}
+
+
+
+ {t('common.required')}
+
+
+ {t('contact.first_name')}
+
+
+
+
+ {t('common.required')}
+
+
+
+ {t('contact.last_name')}
+
+
+
+
+ {t('common.required')}
+
+
+
+ {t('contact.initials')}
+
+
+
+
+
+ {t('contact.visual')}
+
+
+
+
+
+ {t('contact.primary_email')}
+
+
+
+
+ {t('common.required')}
+
+
+
+ {t('contact.secondary_email')}
+
+
+
+ {t('common.required')}
+
+
+ Landlines
+
+
+ ({ value: opt, label: opt }))}
+ placeholder={t('common.type_for_options')}
+ />
+
+
+ Mobiles
+
+
+ ({ value: opt, label: opt }))}
+ placeholder={t('common.type_for_options')}
+ />
+
+
+ {t('user.description')}
+
+
+
+
+
+ {t('user.note')}
+
+
+
+
+
+
+
+ {t('entity.selected_entity')}
+
+
+ {fields.entity.value === '' ? t('entity.need_select_entity') : selectedEntity}
+
+
+
+ setFilter(e.target.value)}
+ />
+ (
+ |
+ `/configuration/${item.id}`}
+ >
+ {item.name}
+
+ |
+ ),
+ created: (item) => (
+
+
+ |
+ ),
+ actions: (item) => (
+
+
+ selectEntity(item)}>
+
+
+
+ |
+ ),
+ }}
+ />
+
+
+ );
+};
+
+AddContactForm.propTypes = {
+ t: PropTypes.func.isRequired,
+ disable: PropTypes.bool.isRequired,
+ fields: PropTypes.instanceOf(Object).isRequired,
+ updateField: PropTypes.func.isRequired,
+ updateFieldWithKey: PropTypes.func.isRequired,
+ entities: PropTypes.instanceOf(Array).isRequired,
+};
+
+export default AddContactForm;
diff --git a/src/components/Configuration/CustomMultiModal/index.js b/src/components/Configuration/CustomMultiModal/index.js
index 035f839..384fc2a 100644
--- a/src/components/Configuration/CustomMultiModal/index.js
+++ b/src/components/Configuration/CustomMultiModal/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import {
CFormGroup,
@@ -13,7 +13,7 @@ import {
CDataTable,
} from '@coreui/react';
import CIcon from '@coreui/icons-react';
-import { cilMinus, cilSave, cilX } from '@coreui/icons';
+import { cilMinus, cilPlus, cilSave, cilX } from '@coreui/icons';
import useToggle from '../../../hooks/useToggle';
const CustomMultiModal = ({
@@ -28,15 +28,17 @@ const CustomMultiModal = ({
secondCol,
length,
modalSize,
+ itemName,
+ noTable,
+ toggleAdd,
+ reset,
}) => {
const [show, toggle] = useToggle();
const getLabel = () => {
- if (length === 0) return t('common.add_items');
+ if (length === 0) return `Manage ${itemName}`;
- if (length === 1) return `${length} ${t('common.item')}`;
-
- return `${length} ${t('common.items')}`;
+ return `Manage ${itemName} (${length})`;
};
const remove = (v) => {
@@ -55,6 +57,10 @@ const CustomMultiModal = ({
toggle();
};
+ useEffect(() => {
+ if (show && reset !== null) reset();
+ }, [show]);
+
return (
@@ -69,6 +75,17 @@ const CustomMultiModal = ({
{label}
+
+
+
+
+
@@ -83,22 +100,29 @@ const CustomMultiModal = ({
{children}
- (
-
- remove(item)}>
-
-
- |
- ),
- }}
- />
+ {!noTable ? (
+ (
+
+ remove(item)}
+ >
+
+
+ |
+ ),
+ }}
+ />
+ ) : null}
@@ -117,12 +141,19 @@ CustomMultiModal.propTypes = {
secondCol: PropTypes.string,
length: PropTypes.number.isRequired,
modalSize: PropTypes.string,
+ itemName: PropTypes.string.isRequired,
+ noTable: PropTypes.bool,
+ toggleAdd: PropTypes.func,
+ reset: PropTypes.func,
};
CustomMultiModal.defaultProps = {
firstCol: 6,
secondCol: 6,
modalSize: 'lg',
+ noTable: false,
+ toggleAdd: null,
+ reset: null,
};
export default CustomMultiModal;
diff --git a/src/components/Configuration/FileField/index.js b/src/components/Configuration/FileField/index.js
new file mode 100644
index 0000000..4eb8287
--- /dev/null
+++ b/src/components/Configuration/FileField/index.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { CFormGroup, CCol, CLabel, CInvalidFeedback } from '@coreui/react';
+
+const textToShow = (fieldValue, fileName) => {
+ if (fieldValue === '') return 'Not uploaded yet';
+ if (fileName === '') return 'Filename unavailable';
+ return `(using file: ${fileName})`;
+};
+
+const StringField = ({
+ fileName,
+ fieldValue,
+ label,
+ firstCol,
+ secondCol,
+ errorMessage,
+ extraButton,
+}) => (
+
+
+ {label}
+
+
+ {textToShow(fieldValue, fileName)}
+ {extraButton}
+ {errorMessage}
+
+
+);
+
+StringField.propTypes = {
+ fieldValue: PropTypes.string.isRequired,
+ fileName: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ firstCol: PropTypes.string,
+ secondCol: PropTypes.string,
+ errorMessage: PropTypes.string,
+ extraButton: PropTypes.node,
+};
+
+StringField.defaultProps = {
+ firstCol: 6,
+ secondCol: 6,
+ errorMessage: '',
+ extraButton: null,
+};
+
+export default StringField;
diff --git a/src/components/Configuration/Select/index.js b/src/components/Configuration/Select/index.js
index 96a259f..d56207b 100644
--- a/src/components/Configuration/Select/index.js
+++ b/src/components/Configuration/Select/index.js
@@ -27,6 +27,16 @@ const ConfigurationSelectField = ({
return null;
}
+ if (typeof field.options[0] === 'number') {
+ for (const opt of field.options) {
+ const value = opt;
+ if (value === field.value) {
+ return { value, label: opt };
+ }
+ }
+ return null;
+ }
+
if (options !== null) {
for (const opt of options) {
if (field.value === opt.value) return opt;
@@ -34,7 +44,10 @@ const ConfigurationSelectField = ({
}
for (const opt of field.options) {
- if (field.value === opt.value) return opt;
+ if (field.value === opt.value) {
+ if (field.mergeOptions) return { value: opt.value, label: `${opt.label} (${opt.value})` };
+ return opt;
+ }
}
return null;
@@ -42,10 +55,22 @@ const ConfigurationSelectField = ({
const parseOptions = () => {
if (options !== null) return options;
- if (typeof field.options[0] !== 'string') {
+ if (typeof field.options[0] !== 'string' && typeof field.options[0] !== 'number') {
+ if (field.mergeOptions)
+ return field.options.map((opt) => ({
+ value: opt.value,
+ label: `${opt.label} (${opt.value})`,
+ }));
return field.options;
}
+ if (typeof field.options[0] === 'number') {
+ return field.options.map((opt) => ({
+ value: opt,
+ label: `${opt}`,
+ }));
+ }
+
if (field.options[0].includes('(')) {
return field.options.map((opt) => ({
value: opt.split('(')[1].split(')')[0],
@@ -54,7 +79,7 @@ const ConfigurationSelectField = ({
}
return field.options.map((opt) => ({
value: opt,
- label: `opt${field.unit ?? ''}`,
+ label: `${opt}${field.unit ?? ''}`,
}));
};
@@ -64,7 +89,7 @@ const ConfigurationSelectField = ({
{label}
-
+
@@ -77,6 +107,7 @@ StringField.propTypes = {
disabled: PropTypes.bool.isRequired,
width: PropTypes.string,
placeholder: PropTypes.string,
+ extraButton: PropTypes.node,
};
StringField.defaultProps = {
@@ -85,6 +116,7 @@ StringField.defaultProps = {
errorMessage: '',
width: null,
placeholder: null,
+ extraButton: null,
};
export default StringField;
diff --git a/src/components/ContactTable/DeleteButton.js b/src/components/ContactTable/DeleteButton.js
new file mode 100644
index 0000000..729b865
--- /dev/null
+++ b/src/components/ContactTable/DeleteButton.js
@@ -0,0 +1,88 @@
+import React, { useState } from 'react';
+import ReactTooltip from 'react-tooltip';
+import { v4 as createUuid } from 'uuid';
+import { CButton, CCardBody, CCardHeader, CRow, CCol, CPopover, CButtonClose } from '@coreui/react';
+import { cilTrash } from '@coreui/icons';
+import CIcon from '@coreui/icons-react';
+import PropTypes from 'prop-types';
+import LoadingButton from '../LoadingButton';
+
+import styles from './index.module.scss';
+
+const DeleteButton = ({ t, contact, deleteContact, hideTooltips }) => {
+ const [tooltipId] = useState(createUuid());
+
+ return (
+
+
+
+
+
+ {
+ const element = document.getElementById(tooltipId);
+ const tooltipWidth = element ? element.offsetWidth : 0;
+ const newLeft = left - tooltipWidth * 0.4;
+ return { top, left: newLeft };
+ }}
+ >
+
+ {t('inventory.delete_tag')}
+ {
+ e.target.parentNode.parentNode.classList.remove('show');
+ hideTooltips();
+ }}
+ />
+
+
+
+
+ deleteContact(contact.id)}
+ block
+ disabled={false}
+ />
+
+
+
+
+
+
+ );
+};
+
+DeleteButton.propTypes = {
+ t: PropTypes.func.isRequired,
+ contact: PropTypes.instanceOf(Object).isRequired,
+ deleteContact: PropTypes.func.isRequired,
+ hideTooltips: PropTypes.func.isRequired,
+};
+
+export default DeleteButton;
diff --git a/src/components/ContactTable/UnassignButton.js b/src/components/ContactTable/UnassignButton.js
new file mode 100644
index 0000000..4e3bc84
--- /dev/null
+++ b/src/components/ContactTable/UnassignButton.js
@@ -0,0 +1,90 @@
+import React, { useState } from 'react';
+import ReactTooltip from 'react-tooltip';
+import { v4 as createUuid } from 'uuid';
+import { CButton, CCardBody, CCardHeader, CRow, CCol, CPopover, CButtonClose } from '@coreui/react';
+import { cilMinus } from '@coreui/icons';
+import CIcon from '@coreui/icons-react';
+import PropTypes from 'prop-types';
+import LoadingButton from '../LoadingButton';
+
+import styles from './index.module.scss';
+
+const UnassignButton = ({ t, contact, unassignContact, hideTooltips, disabled }) => {
+ const [tooltipId] = useState(createUuid());
+
+ return (
+
+
+
+
+
+ {
+ const element = document.getElementById(tooltipId);
+ const tooltipWidth = element ? element.offsetWidth : 0;
+ const newLeft = left - tooltipWidth * 0.4;
+ return { top, left: newLeft };
+ }}
+ >
+
+ {t('inventory.unassign_tag')}
+ {
+ e.target.parentNode.parentNode.classList.remove('show');
+ hideTooltips();
+ }}
+ />
+
+
+
+
+ unassignContact(contact.serialNumber)}
+ block
+ disabled={false}
+ />
+
+
+
+
+
+
+ );
+};
+
+UnassignButton.propTypes = {
+ t: PropTypes.func.isRequired,
+ contact: PropTypes.instanceOf(Object).isRequired,
+ unassignContact: PropTypes.func.isRequired,
+ hideTooltips: PropTypes.func.isRequired,
+ disabled: PropTypes.bool.isRequired,
+};
+
+export default UnassignButton;
diff --git a/src/components/ContactTable/index.js b/src/components/ContactTable/index.js
new file mode 100644
index 0000000..395151a
--- /dev/null
+++ b/src/components/ContactTable/index.js
@@ -0,0 +1,181 @@
+import React, { useEffect } from 'react';
+import PropTypes from 'prop-types';
+import { CButton, CDataTable, CLink, CPopover, CButtonToolbar } from '@coreui/react';
+import { cilPencil, cilPlus } from '@coreui/icons';
+import CIcon from '@coreui/icons-react';
+import ReactTooltip from 'react-tooltip';
+import DeleteButton from './DeleteButton';
+import UnassignButton from './UnassignButton';
+import FormattedDate from '../FormattedDate';
+
+const ContactTable = ({
+ t,
+ loading,
+ entity,
+ filterOnEntity,
+ contacts,
+ unassign,
+ assignToEntity,
+ toggleEditModal,
+ deleteContact,
+ perPageSwitcher,
+ pageSwitcher,
+}) => {
+ const columns = filterOnEntity
+ ? [
+ { key: 'primaryEmail', label: t('contact.primary_email'), _style: { width: '15%' } },
+ { key: 'name', label: t('user.name'), _style: { width: '10%' } },
+ { key: 'description', label: t('user.description'), _style: { width: '20%' } },
+ { key: 'created', label: t('common.created'), _style: { width: '10%' } },
+ { key: 'actions', label: t('actions.actions'), _style: { width: '1%' } },
+ ]
+ : [
+ { key: 'primaryEmail', label: t('contact.primary_email'), _style: { width: '15%' } },
+ { key: 'name', label: t('user.name'), _style: { width: '10%' } },
+ { key: 'description', label: t('user.description'), _style: { width: '20%' } },
+ { key: 'entity', label: t('entity.entity'), _style: { width: '10%' } },
+ { key: 'created', label: t('common.created'), _style: { width: '12%' } },
+ { key: 'modified', label: t('common.modified'), _style: { width: '12%' } },
+ { key: 'actions', label: t('actions.actions'), _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);
+ };
+ }, []);
+
+ return (
+ <>
+
(
+
+ {item.firstname} {item.lastname}
+ |
+ ),
+ created: (item) => (
+
+
+ |
+ ),
+ modified: (item) => (
+
+
+ |
+ ),
+ description: (item) => {item.description} | ,
+ entity: (item) => (
+
+ {filterOnEntity ? (
+ item.entity
+ ) : (
+ `/entity/${item.entity}`}
+ >
+ {item.extendedInfo?.entity?.name ?? item.entity}
+
+ )}
+ |
+ ),
+ actions: (item) => (
+
+
+
+
+ assignToEntity(item.id)}
+ style={{ width: '33px', height: '30px' }}
+ >
+
+
+
+
+
+
+
+ toggleEditModal(item.id)}
+ style={{ width: '33px', height: '30px' }}
+ >
+
+
+
+
+ |
+ ),
+ }}
+ />
+
+ {pageSwitcher}
+
{t('common.items_per_page')}
+ {perPageSwitcher}
+
+ >
+ );
+};
+
+ContactTable.propTypes = {
+ t: PropTypes.func.isRequired,
+ loading: PropTypes.bool.isRequired,
+ entity: PropTypes.instanceOf(Object),
+ filterOnEntity: PropTypes.bool,
+ contacts: PropTypes.instanceOf(Array).isRequired,
+ unassign: PropTypes.func.isRequired,
+ assignToEntity: PropTypes.func.isRequired,
+ toggleEditModal: PropTypes.func.isRequired,
+ deleteContact: PropTypes.func.isRequired,
+ perPageSwitcher: PropTypes.node.isRequired,
+ pageSwitcher: PropTypes.node.isRequired,
+};
+
+ContactTable.defaultProps = {
+ filterOnEntity: false,
+ entity: null,
+};
+
+export default ContactTable;
diff --git a/src/components/ContactTable/index.module.scss b/src/components/ContactTable/index.module.scss
new file mode 100644
index 0000000..0da2908
--- /dev/null
+++ b/src/components/ContactTable/index.module.scss
@@ -0,0 +1,28 @@
+.unassignTooltip {
+ 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 rgb(0 0 0 / 0.2) !important;
+ width: 300px;
+}
+
+.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 rgb(0 0 0 / 0.2) !important;
+ width: 200px;
+}
+
+.tooltipHeader {
+ border-top-left-radius: 1rem !important;
+ border-top-right-radius: 1rem !important;
+}
diff --git a/src/components/CreateUserForm/index.js b/src/components/CreateUserForm/index.js
index 7c606d4..16e77d6 100644
--- a/src/components/CreateUserForm/index.js
+++ b/src/components/CreateUserForm/index.js
@@ -46,8 +46,11 @@ const CreateUserForm = ({ t, fields, updateField, policies, toggleChange }) => {
+
+
+
diff --git a/src/components/EditConfigurationForm/index.js b/src/components/EditConfigurationForm/index.js
index 45af12c..f19d1d4 100644
--- a/src/components/EditConfigurationForm/index.js
+++ b/src/components/EditConfigurationForm/index.js
@@ -85,10 +85,10 @@ const EditConfigurationForm = ({
-
+
{t('user.name')}:
-
+
{editing ? (
-
+
{t('user.description')}:
-
+
{editing ? (
-
+
{t('configuration.device_types')}:
-
+
-
+
RRM:
-
+