From ac6b38c740bff348ac66c061198b053c73a86ffa Mon Sep 17 00:00:00 2001 From: Michael O'Toole Date: Fri, 14 Jan 2022 11:40:24 +0000 Subject: [PATCH 1/2] Fix for layout on AutopilotAddDevice. --- .mega-linter.yml | 2 +- .vscode/launch.json | 2 +- package.json | 2 +- src/scss/_custom.scss | 4 ++++ .../endpoint/autopilot/AutopilotAddDevice.js | 24 +++++++++---------- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.mega-linter.yml b/.mega-linter.yml index 57c8c90a6657..1eccaa23246b 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -4,6 +4,6 @@ APPLY_FIXES: none SHOW_ELAPSED_TIME: true FILEIO_REPORTER: false -ENABLE: [CSS, HTML, JSON, YAML, JSX, ACTION] +ENABLE: [CSS, HTML, JSON, YAML, JSX, ACTION, CREDENTIALS] DISABLE_LINTERS: [CSS_SCSS_LINT, YAML_PRETTIER] SHOW_SKIPPED_LINTERS: false diff --git a/.vscode/launch.json b/.vscode/launch.json index e09338d97e3f..32f6a9501912 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,7 +2,7 @@ "version": "0.2.0", "configurations": [ { - "command": "swa start --ssl --ssl-cert ./.vscode/cert.crt --ssl-key ./.vscode/key.key --swa-config-location . http://localhost:3000 --api-location http://localhost:7071", + "command": "npm run start-api", "name": "Run emulator", "request": "launch", "type": "node-terminal" diff --git a/package.json b/package.json index 83c1409d7b2d..1d00df22eb8b 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "test": "react-scripts test", "test:cov": "npm test -- --coverage --watchAll=false", "test:debug": "react-scripts --inspect-brk test --runInBand", - "start-api": "swa start --ssl --ssl-cert ./.vscode/cert.crt --ssl-key ./.vscode/key.key --swa-config-location . http://localhost:3000 --api-location http://localhost:7071", + "start-api": "swa start --ssl --ssl-cert ./.vscode/cert.crt --ssl-key ./.vscode/key.key --swa-config-location . http://localhost:3000 --api-location http://localhost:7071 --swa-config-location .vscode", "prepare": "husky install" }, "config": { diff --git a/src/scss/_custom.scss b/src/scss/_custom.scss index 6c17357204c2..7646f424a220 100644 --- a/src/scss/_custom.scss +++ b/src/scss/_custom.scss @@ -264,3 +264,7 @@ top: 0.1rem; } } + +.btn-as-block { + display: block; +} diff --git a/src/views/endpoint/autopilot/AutopilotAddDevice.js b/src/views/endpoint/autopilot/AutopilotAddDevice.js index 0f5625021459..5f894bea023e 100644 --- a/src/views/endpoint/autopilot/AutopilotAddDevice.js +++ b/src/views/endpoint/autopilot/AutopilotAddDevice.js @@ -1,9 +1,8 @@ import React from 'react' -import { CAlert, CButton, CCol, CFormLabel, CRow } from '@coreui/react' +import { CAlert, CButton, CCol, CRow } from '@coreui/react' import { Field } from 'react-final-form' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' -import { useSelector } from 'react-redux' +import { faExclamationTriangle, faPlus } from '@fortawesome/free-solid-svg-icons' import Wizard from '../../../components/Wizard' import PropTypes from 'prop-types' import { RFFCFormInput } from '../../../components/RFFComponents' @@ -29,8 +28,6 @@ Error.propTypes = { } const AddAPDevice = () => { - const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) - const handleSubmit = async (values) => { alert(JSON.stringify(values, null, 2)) // @todo hook this up @@ -74,23 +71,26 @@ const AddAPDevice = () => {

- + - + - + - + - + - - Add + + + + Add +
From a4540cff8318e608fe71d263b88f4f9877b9809e Mon Sep 17 00:00:00 2001 From: Michael O'Toole Date: Fri, 14 Jan 2022 12:55:35 +0000 Subject: [PATCH 2/2] Replace keyboard input handling. --- package-lock.json | 31 +++ package.json | 1 + src/assets/brand/logo-negative.js | 33 --- src/assets/brand/logo.js | 32 --- src/assets/brand/sygnet.js | 12 - src/components/AppBreadcrumb.js | 2 +- src/components/AppHeader.js | 4 +- src/components/AppSidebar.js | 6 +- src/components/CippPage.js | 8 +- src/components/CippProfile.js | 4 +- src/components/FastSwitcher.js | 2 +- src/components/ModalRoot.js | 2 +- src/components/PrivateRoute.js | 6 +- src/components/SharedModal.js | 2 +- src/components/Toasts.js | 2 +- src/components/Wizard.js | 2 +- src/components/WizardTableField.js | 2 +- src/components/cipp/CippDatatable.js | 4 +- src/components/cipp/TenantSelector.js | 4 +- src/components/cipp/TenantSelectorMultiple.js | 2 +- src/components/cipp/index.js | 36 +-- src/components/header/AppHeaderDropdown.js | 6 +- src/components/index.js | 22 +- src/hooks/useConfirmModal.js | 2 +- src/hooks/useKeyboardShortcut.js | 218 ------------------ src/layout/DefaultLayout.js | 20 +- src/views/home/Home.js | 6 +- .../administration/ConditionalAccess.js | 2 +- 28 files changed, 112 insertions(+), 361 deletions(-) delete mode 100644 src/assets/brand/logo-negative.js delete mode 100644 src/assets/brand/logo.js delete mode 100644 src/assets/brand/sygnet.js delete mode 100644 src/hooks/useKeyboardShortcut.js diff --git a/package-lock.json b/package-lock.json index 02e54cf44320..e4f51ff07212 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "react-dom": "^17.0.2", "react-final-form": "^6.5.7", "react-final-form-listeners": "^1.0.3", + "react-hotkeys-hook": "^3.4.4", "react-media-hook": "^0.4.9", "react-papaparse": "^3.18.2", "react-redux": "^7.2.5", @@ -10288,6 +10289,11 @@ "node": ">=10" } }, + "node_modules/hotkeys-js": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.8.7.tgz", + "integrity": "sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg==" + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -17014,6 +17020,18 @@ "react-final-form": ">=3.0.0" } }, + "node_modules/react-hotkeys-hook": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.4.tgz", + "integrity": "sha512-vaORq07rWgmuF3owWRhgFV/3VL8/l2q9lz0WyVEddJnWTtKW+AOgU5YgYKuwN6h6h7bCcLG3MFsJIjCrM/5DvQ==", + "dependencies": { + "hotkeys-js": "3.8.7" + }, + "peerDependencies": { + "react": ">=16.8.1", + "react-dom": ">=16.8.1" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -29145,6 +29163,11 @@ "lru-cache": "^6.0.0" } }, + "hotkeys-js": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.8.7.tgz", + "integrity": "sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg==" + }, "hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -34065,6 +34088,14 @@ "@babel/runtime": "^7.12.5" } }, + "react-hotkeys-hook": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.4.tgz", + "integrity": "sha512-vaORq07rWgmuF3owWRhgFV/3VL8/l2q9lz0WyVEddJnWTtKW+AOgU5YgYKuwN6h6h7bCcLG3MFsJIjCrM/5DvQ==", + "requires": { + "hotkeys-js": "3.8.7" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", diff --git a/package.json b/package.json index 1d00df22eb8b..617d44306542 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "react-dom": "^17.0.2", "react-final-form": "^6.5.7", "react-final-form-listeners": "^1.0.3", + "react-hotkeys-hook": "^3.4.4", "react-media-hook": "^0.4.9", "react-papaparse": "^3.18.2", "react-redux": "^7.2.5", diff --git a/src/assets/brand/logo-negative.js b/src/assets/brand/logo-negative.js deleted file mode 100644 index 114a6a04732f..000000000000 --- a/src/assets/brand/logo-negative.js +++ /dev/null @@ -1,33 +0,0 @@ -export const logoNegative = [ - '608 134', - ` - coreui react pro logo - - - - - - - - - - - - - - - - - - - - - - - - - - - -`, -] diff --git a/src/assets/brand/logo.js b/src/assets/brand/logo.js deleted file mode 100644 index 7a2d7e0b3d89..000000000000 --- a/src/assets/brand/logo.js +++ /dev/null @@ -1,32 +0,0 @@ -export const logo = [ - '608 134', - ` - coreui react pro - - - - - - - - - - - - - - - - - - - - - - - - - - -`, -] diff --git a/src/assets/brand/sygnet.js b/src/assets/brand/sygnet.js deleted file mode 100644 index 3a57fbdd4c9f..000000000000 --- a/src/assets/brand/sygnet.js +++ /dev/null @@ -1,12 +0,0 @@ -export const sygnet = [ - '160 160', - ` - coreui logo - - - - - - -`, -] diff --git a/src/components/AppBreadcrumb.js b/src/components/AppBreadcrumb.js index 4ab0f0f29880..b976fbfa985f 100644 --- a/src/components/AppBreadcrumb.js +++ b/src/components/AppBreadcrumb.js @@ -1,7 +1,7 @@ import React from 'react' import { useLocation } from 'react-router-dom' -import routes from '../routes' +import routes from 'src/routes' import { CBreadcrumb, CBreadcrumbItem } from '@coreui/react' diff --git a/src/components/AppHeader.js b/src/components/AppHeader.js index b03aeac735fa..7a35f4b17516 100644 --- a/src/components/AppHeader.js +++ b/src/components/AppHeader.js @@ -11,11 +11,11 @@ import { } from '@coreui/react' import { faBars } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { AppBreadcrumb } from './index' +import AppBreadcrumb from 'src/components/AppBreadcrumb' import AppHeaderDropdown from 'src/components/header/AppHeaderDropdown' import AppHeaderSearch from 'src/components/header/AppHeaderSearch' import cyberdrainlogo from 'src/assets/images/CIPP.png' -import { toggleSidebarShow } from '../store/features/app' +import { toggleSidebarShow } from 'src/store/features/app' const AppHeader = () => { const dispatch = useDispatch() diff --git a/src/components/AppSidebar.js b/src/components/AppSidebar.js index 71252ebfdc6a..7c471264c77f 100644 --- a/src/components/AppSidebar.js +++ b/src/components/AppSidebar.js @@ -2,12 +2,12 @@ import React from 'react' import { useSelector, useDispatch } from 'react-redux' import { CSidebar, CSidebarBrand, CSidebarNav } from '@coreui/react' import { CImage } from '@coreui/react' -import { AppSidebarNav } from './AppSidebarNav' +import { AppSidebarNav } from 'src/components/AppSidebarNav' import cyberdrainlogo from 'src/assets/images/CIPP.png' import SimpleBar from 'simplebar-react' import 'simplebar/dist/simplebar.min.css' -import navigation from '../_nav' -import { setSidebarVisible } from '../store/features/app' +import navigation from 'src/_nav' +import { setSidebarVisible } from 'src/store/features/app' const AppSidebar = () => { const dispatch = useDispatch() diff --git a/src/components/CippPage.js b/src/components/CippPage.js index ef0c48128e4a..86e626b4bf36 100644 --- a/src/components/CippPage.js +++ b/src/components/CippPage.js @@ -1,12 +1,12 @@ import React, { useEffect } from 'react' import PropTypes from 'prop-types' -import TenantSelector from './cipp/TenantSelector' +import TenantSelector from 'src/components/cipp/TenantSelector' import { CAlert, CCard, CCardBody, CCardHeader } from '@coreui/react' -import CippDatatable from './cipp/CippDatatable' +import CippDatatable from 'src/components/cipp/CippDatatable' import { useDispatch, useSelector } from 'react-redux' import { useSearchParams } from 'react-router-dom' -import { setCurrentTenant } from '../store/features/app' -import { useListTenantsQuery } from '../store/api/tenants' +import { setCurrentTenant } from 'src/store/features/app' +import { useListTenantsQuery } from 'src/store/api/tenants' export function CippPage({ tenantSelector = true, title, children, titleButton = null }) { const { data: tenants = [], isSuccess } = useListTenantsQuery() diff --git a/src/components/CippProfile.js b/src/components/CippProfile.js index d75ba9300f02..dab9ce7c925f 100644 --- a/src/components/CippProfile.js +++ b/src/components/CippProfile.js @@ -10,8 +10,8 @@ import { CListGroupItem, CSpinner, } from '@coreui/react' -import avatar0 from './../assets/images/avatars/0.jpg' -import { useLoadClientPrincipalQuery } from '../store/api/auth' +import avatar0 from 'src/assets/images/avatars/0.jpg' +import { useLoadClientPrincipalQuery } from 'src/store/api/auth' import ThemeSwitcher from 'src/components/cipp/ThemeSwitcher' const CippProfile = () => { diff --git a/src/components/FastSwitcher.js b/src/components/FastSwitcher.js index 5b3e1341bdbd..598623da41ae 100644 --- a/src/components/FastSwitcher.js +++ b/src/components/FastSwitcher.js @@ -1,7 +1,7 @@ import React, { useEffect, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { CFormInput, CModal, CModalBody } from '@coreui/react' -import { hideSwitcher, mapNav } from '../store/features/switcher' +import { hideSwitcher, mapNav } from 'src/store/features/switcher' import { useNavigate } from 'react-router-dom' import PropTypes from 'prop-types' //import FuzzySearch from 'fuzzy-search' diff --git a/src/components/ModalRoot.js b/src/components/ModalRoot.js index b85e0de44025..61d3d03359e1 100644 --- a/src/components/ModalRoot.js +++ b/src/components/ModalRoot.js @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { SharedModal } from './index' +import SharedModal from 'src/components/SharedModal' export const ModalService = { on(event, callback) { diff --git a/src/components/PrivateRoute.js b/src/components/PrivateRoute.js index b69dd5b42a59..40a025ea9047 100644 --- a/src/components/PrivateRoute.js +++ b/src/components/PrivateRoute.js @@ -1,9 +1,9 @@ import React from 'react' import { Navigate } from 'react-router-dom' -import { useLoadClientPrincipalQuery } from '../store/api/auth' -import { FullScreenLoading } from './Loading' +import { useLoadClientPrincipalQuery } from 'src/store/api/auth' +import { FullScreenLoading } from 'src/components/Loading' import { useDispatch } from 'react-redux' -import { updateAccessToken } from '../store/features/auth' +import { updateAccessToken } from 'src/store/features/auth' import PropTypes from 'prop-types' export const PrivateRoute = ({ children }) => { diff --git a/src/components/SharedModal.js b/src/components/SharedModal.js index 6584f01a9829..514380564fd2 100644 --- a/src/components/SharedModal.js +++ b/src/components/SharedModal.js @@ -1,7 +1,7 @@ import React from 'react' import { CButton, CModal, CModalBody, CModalFooter, CModalHeader, CModalTitle } from '@coreui/react' import PropTypes from 'prop-types' -import { CippTable } from './cipp' +import CippTable from 'src/components/cipp/CippTable' /** * diff --git a/src/components/Toasts.js b/src/components/Toasts.js index 392a5bed9b45..d8acfeda6b7c 100644 --- a/src/components/Toasts.js +++ b/src/components/Toasts.js @@ -4,7 +4,7 @@ import { useDispatch, useSelector } from 'react-redux' import { CToast, CToastBody, CToaster, CToastHeader, CCollapse } from '@coreui/react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faExpandAlt, faCompressAlt, faTimes } from '@fortawesome/free-solid-svg-icons' -import { closeToast } from '../store/features/toasts' +import { closeToast } from 'src/store/features/toasts' const Toasts = () => { const dispatch = useDispatch() diff --git a/src/components/Wizard.js b/src/components/Wizard.js index a01722964ae6..aa601231a8ba 100644 --- a/src/components/Wizard.js +++ b/src/components/Wizard.js @@ -2,7 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import { Form } from 'react-final-form' import { CButton, CCardHeader, CNav, CNavItem, CNavLink, CRow, CCol } from '@coreui/react' -import { CippPage } from 'src/components' +import { CippPage } from 'src/components/CippPage' export default class Wizard extends React.Component { static propTypes = { diff --git a/src/components/WizardTableField.js b/src/components/WizardTableField.js index 13a0912dfa1c..c117be1aab9e 100644 --- a/src/components/WizardTableField.js +++ b/src/components/WizardTableField.js @@ -1,6 +1,6 @@ import React from 'react' import PropTypes from 'prop-types' -import { CippDatatable } from './cipp' +import CippDatatable from 'src/components/cipp/CippDatatable' /** * Table with checkboxes diff --git a/src/components/cipp/CippDatatable.js b/src/components/cipp/CippDatatable.js index 88e3a60ba96d..fe80173586d6 100644 --- a/src/components/cipp/CippDatatable.js +++ b/src/components/cipp/CippDatatable.js @@ -1,7 +1,7 @@ import React from 'react' -import { useListDatatableQuery } from '../../store/api/datatable' +import { useListDatatableQuery } from 'src/store/api/datatable' import PropTypes from 'prop-types' -import CippTable, { CippTablePropTypes } from './CippTable' +import CippTable, { CippTablePropTypes } from 'src/components/cipp/CippTable' export default function CippDatatable({ path, params, ...rest }) { const { data = [], isFetching, error } = useListDatatableQuery({ path, params }) diff --git a/src/components/cipp/TenantSelector.js b/src/components/cipp/TenantSelector.js index 549f3adc4144..5287bcb06347 100644 --- a/src/components/cipp/TenantSelector.js +++ b/src/components/cipp/TenantSelector.js @@ -2,8 +2,8 @@ import React from 'react' import SelectSearch, { fuzzySearch } from 'react-select-search' import { useDispatch, useSelector } from 'react-redux' import PropTypes from 'prop-types' -import { useListTenantsQuery } from '../../store/api/tenants' -import { setCurrentTenant } from '../../store/features/app' +import { useListTenantsQuery } from 'src/store/api/tenants' +import { setCurrentTenant } from 'src/store/features/app' const TenantSelector = ({ action }) => { const dispatch = useDispatch() diff --git a/src/components/cipp/TenantSelectorMultiple.js b/src/components/cipp/TenantSelectorMultiple.js index da1c8c7920fe..72a30f1c8633 100644 --- a/src/components/cipp/TenantSelectorMultiple.js +++ b/src/components/cipp/TenantSelectorMultiple.js @@ -1,5 +1,5 @@ import React from 'react' -import { useListTenantsQuery } from '../../store/api/tenants' +import { useListTenantsQuery } from 'src/store/api/tenants' import SelectSearch, { fuzzySearch } from 'react-select-search' import PropTypes from 'prop-types' diff --git a/src/components/cipp/index.js b/src/components/cipp/index.js index 93f6403c0703..3e5a093dadee 100644 --- a/src/components/cipp/index.js +++ b/src/components/cipp/index.js @@ -1,21 +1,21 @@ -import { CellBadge, cellBadgeFormatter } from './CellBadge' -import { CellBoolean, cellBooleanFormatter } from './CellBoolean' -import { CellDate, cellDateFormatter } from './CellDate' -import { CellNullText, cellNullTextFormatter } from './CellNullText' -import { CellProgressBar, cellProgressBarFormatter } from './CellProgressBar' -import CippTable from './CippTable' -import CippDatatable from './CippDatatable' -import PdfButton from './PdfButton' -import CsvButton from './CsvButton' -import StatusIcon from './StatusIcon' -import TenantSelector from './TenantSelector' -import TenantSelectorMultiple from './TenantSelectorMultiple' -import ThemeSwitcher from './ThemeSwitcher' -import TitleButton from './TitleButton' -import CippOffcanvas from './CippOffcanvas' -import CippActionsOffcanvas from './CippActionsOffcanvas' -import CippOffcanvasTable from './CippOffcanvasTable' -import CippCodeBlock from './CippCodeBlock' +import { CellBadge, cellBadgeFormatter } from 'src/components/cipp/CellBadge' +import { CellBoolean, cellBooleanFormatter } from 'src/components/cipp/CellBoolean' +import { CellDate, cellDateFormatter } from 'src/components/cipp/CellDate' +import { CellNullText, cellNullTextFormatter } from 'src/components/cipp/CellNullText' +import { CellProgressBar, cellProgressBarFormatter } from 'src/components/cipp/CellProgressBar' +import CippTable from 'src/components/cipp/CippTable' +import CippDatatable from 'src/components/cipp/CippDatatable' +import PdfButton from 'src/components/cipp/PdfButton' +import CsvButton from 'src/components/cipp/CsvButton' +import StatusIcon from 'src/components/cipp/StatusIcon' +import TenantSelector from 'src/components/cipp/TenantSelector' +import TenantSelectorMultiple from 'src/components/cipp/TenantSelectorMultiple' +import ThemeSwitcher from 'src/components/cipp/ThemeSwitcher' +import TitleButton from 'src/components/cipp/TitleButton' +import CippOffcanvas from 'src/components/cipp/CippOffcanvas' +import CippActionsOffcanvas from 'src/components/cipp/CippActionsOffcanvas' +import CippOffcanvasTable from 'src/components/cipp/CippOffcanvasTable' +import CippCodeBlock from 'src/components/cipp/CippCodeBlock' export { CellBadge, diff --git a/src/components/header/AppHeaderDropdown.js b/src/components/header/AppHeaderDropdown.js index 2871efbaec87..913259bd534a 100644 --- a/src/components/header/AppHeaderDropdown.js +++ b/src/components/header/AppHeaderDropdown.js @@ -10,9 +10,9 @@ import { import { faUser, faBook, faSignOutAlt } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Link } from 'react-router-dom' -import { authApi } from '../../store/api/auth' -import CippProfile from '../CippProfile' -import CippOffcanvas from '../cipp/CippOffcanvas' +import { authApi } from 'src/store/api/auth' +import CippProfile from 'src/components/CippProfile' +import CippOffcanvas from 'src/components/cipp/CippOffcanvas' const AppHeaderDropdown = () => { const [profileVisible, setProfileVisible] = useState(false) diff --git a/src/components/index.js b/src/components/index.js index 3ce250dbf338..c6b9b0ef8a69 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,13 +1,13 @@ -import AppBreadcrumb from './AppBreadcrumb' -import AppFooter from './AppFooter' -import AppHeader from './AppHeader' -import AppHeaderDropdown from './header/AppHeaderDropdown' -import AppHeaderSearch from './header/AppHeaderSearch' -import AppSidebar from './AppSidebar' -import Loading, { FullScreenLoading } from './Loading' -import SharedModal from './SharedModal' -import { ModalRoot, ModalService } from './ModalRoot' -import { CippPage, CippPageList } from './CippPage' +import AppBreadcrumb from 'src/components/AppBreadcrumb' +import AppFooter from 'src/components/AppFooter' +import AppHeader from 'src/components/AppHeader' +import AppHeaderDropdown from 'src/components/header/AppHeaderDropdown' +import AppHeaderSearch from 'src/components/header/AppHeaderSearch' +import AppSidebar from 'src/components/AppSidebar' +import Loading, { FullScreenLoading } from 'src/components/Loading' +import SharedModal from 'src/components/SharedModal' +import { ModalRoot, ModalService } from 'src/components/ModalRoot' +import { CippPage, CippPageList } from 'src/components/CippPage' import { Condition, RFFCFormCheck, @@ -18,7 +18,7 @@ import { RFFCFormSwitch, RFFCFormTextarea, RFFSelectSearch, -} from './RFFComponents' +} from 'src/components/RFFComponents' export { AppBreadcrumb, diff --git a/src/hooks/useConfirmModal.js b/src/hooks/useConfirmModal.js index 46ab78d4088a..13d95fd5a270 100644 --- a/src/hooks/useConfirmModal.js +++ b/src/hooks/useConfirmModal.js @@ -1,5 +1,5 @@ import React from 'react' -import { ModalService } from '../components' +import { ModalService } from 'src/components/ModalRoot' export default function useConfirmModal({ body, diff --git a/src/hooks/useKeyboardShortcut.js b/src/hooks/useKeyboardShortcut.js deleted file mode 100644 index 7ce2c58cf094..000000000000 --- a/src/hooks/useKeyboardShortcut.js +++ /dev/null @@ -1,218 +0,0 @@ -// from https://www.fullstacklabs.co/blog/keyboard-shortcuts-with-react-hooks -import { useEffect, useCallback, useRef, useMemo } from 'react' - -const BLACKLISTED_DOM_TARGETS = ['TEXTAREA', 'INPUT'] - -const DEFAULT_OPTIONS = { - overrideSystem: false, - ignoreInputFields: true, -} - -const useKeyboardShortcut = (shortcutKeys, callback, options = DEFAULT_OPTIONS) => { - if (!Array.isArray(shortcutKeys)) - throw new Error( - 'The first parameter to `useKeyboardShortcut` must be an ordered array of `KeyboardEvent.key` strings.', - ) - - if (!shortcutKeys.length) - throw new Error( - 'The first parameter to `useKeyboardShortcut` must contain atleast one `KeyboardEvent.key` string.', - ) - - if (!callback || typeof callback !== 'function') - throw new Error( - 'The second parameter to `useKeyboardShortcut` must be a function that will be envoked when the keys are pressed.', - ) - - // Normalizes the shortcut keys a deduplicated array of lowercased keys. - const shortcutArray = useMemo( - () => uniq_fast(shortcutKeys).map((key) => String(key).toLowerCase()), - // While using JSON.stringify() is bad for most larger objects, this shortcut - // array is fine as it's small, according to the answer below. - // https://github.com/facebook/react/issues/14476#issuecomment-471199055 - // eslint-disable-next-line react-hooks/exhaustive-deps - [JSON.stringify(shortcutKeys)], - ) - // useRef to avoid a constant re-render on keydown and keyup. - const heldKeys = useRef([]) - - const keydownListener = useCallback( - (keydownEvent) => { - const loweredKey = String(keydownEvent.key).toLowerCase() - if (!(shortcutArray.indexOf(loweredKey) >= 0)) return - - if (keydownEvent.repeat) return - - // This needs to be checked as soon as possible to avoid - // all option checks that might prevent default behavior - // of the key press. - // - // I.E If shortcut is "Shift + A", we shouldn't prevent the - // default browser behavior of Select All Text just because - // "A" is being observed for our custom behavior shortcut. - const isHeldKeyCombinationValid = checkHeldKeysRecursive( - loweredKey, - null, - shortcutArray, - heldKeys.current, - ) - - if (!isHeldKeyCombinationValid) { - return - } - - if ( - options.ignoreInputFields && - BLACKLISTED_DOM_TARGETS.indexOf(keydownEvent.target.tagName) >= 0 - ) { - return - } - if (options.overrideSystem) { - overrideSystemHandling(keydownEvent) - } - - heldKeys.current = [...heldKeys.current, loweredKey] - - if (heldKeys.current.length === shortcutArray.length) { - callback(shortcutKeys) - } - - return false - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [shortcutArray, callback, options.overrideSystem, options.ignoreInputFields], - ) - - const keyupListener = useCallback( - (keyupEvent) => { - const raisedKey = String(keyupEvent.key).toLowerCase() - if (!(shortcutArray.indexOf(raisedKey) >= 0)) return - - const raisedKeyHeldIndex = heldKeys.current.indexOf(raisedKey) - if (!(raisedKeyHeldIndex >= 0)) return - - if ( - options.ignoreInputFields && - BLACKLISTED_DOM_TARGETS.indexOf(keyupEvent.target.tagName) >= 0 - ) { - return - } - if (options.overrideSystem) { - overrideSystemHandling(keyupEvent) - } - - let newHeldKeys = [] - let loopIndex - for (loopIndex = 0; loopIndex < heldKeys.current.length; ++loopIndex) { - if (loopIndex !== raisedKeyHeldIndex) { - newHeldKeys.push(heldKeys.current[loopIndex]) - } - } - heldKeys.current = newHeldKeys - - return false - }, - [shortcutArray, options.overrideSystem, options.ignoreInputFields], - ) - - useEffect(() => { - window.addEventListener('keydown', keydownListener) - window.addEventListener('keyup', keyupListener) - return () => { - window.removeEventListener('keydown', keydownListener) - window.removeEventListener('keyup', keyupListener) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [keydownListener, keyupListener, shortcutArray]) - - // Resets the held keys array if the shortcut keys are changed. - useEffect(() => { - heldKeys.current = [] - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [shortcutArray]) -} - -export default useKeyboardShortcut - -const overrideSystemHandling = (e) => { - if (e) { - if (e.preventDefault) e.preventDefault() - if (e.stopPropagation) { - e.stopPropagation() - } else if (window.event) { - window.event.cancelBubble = true - } - } -} - -// Function stolen from this Stack Overflow answer: -// https: stackoverflow.com/a/9229821 -const uniq_fast = (a) => { - var seen = {} - var out = [] - var len = a.length - var j = 0 - for (var i = 0; i < len; i++) { - var item = a[i] - if (seen[item] !== 1) { - seen[item] = 1 - out[j++] = item - } - } - return out -} - -// The goal for this recursive function is to check to ensure -// that the keys are held down in the correct order of the shortcut. -// I.E if the shortcut array is ["Shift", "E", "A"], this function will ensure -// that "E" is held down before "A", and "Shift" is held down before "E". -const checkHeldKeysRecursive = ( - shortcutKey, - // Tracks the call interation for the recursive function, - // based on the previous index; - shortcutKeyRecursionIndex = 0, - shortcutArray, - heldKeysArray, -) => { - const shortcutIndexOfKey = shortcutArray.indexOf(shortcutKey) - const keyPartOfShortCut = shortcutArray.indexOf(shortcutKey) >= 0 - - // Early exit if they key isn't even in the shortcut combination. - if (!keyPartOfShortCut) return false - - // While holding down one of the keys, if another is to be let go, the shortcut - // should be void. Shortcut keys must be held down in a specifc order. - // This function is always called before a key is added to held keys on keydown, - // this will ensure that heldKeys only contains the prefixing keys - const comparisonIndex = Math.max(heldKeysArray.length - 1, 0) - if (heldKeysArray.length && heldKeysArray[comparisonIndex] !== shortcutArray[comparisonIndex]) { - return false - } - - // Early exit for the first held down key in the shortcut, - // except if this is a recursive call - if (shortcutIndexOfKey === 0) { - // If this isn't the first interation of this recursive function, and we're - // recursively calling this function, we should always be checking the - // currently held down keys instead of returning true - if (shortcutKeyRecursionIndex > 0) return heldKeysArray.indexOf(shortcutKey) >= 0 - return true - } - - const previousShortcutKeyIndex = shortcutIndexOfKey - 1 - const previousShortcutKey = shortcutArray[previousShortcutKeyIndex] - const previousShortcutKeyHeld = heldKeysArray[previousShortcutKeyIndex] === previousShortcutKey - - // Early exit if the key just before the currently checked shortcut key - // isn't being held down. - if (!previousShortcutKeyHeld) return false - - // Recursively call this function with the previous key as the new shortcut key - // but the index of the current shortcut key. - return checkHeldKeysRecursive( - previousShortcutKey, - shortcutIndexOfKey, - shortcutArray, - heldKeysArray, - ) -} diff --git a/src/layout/DefaultLayout.js b/src/layout/DefaultLayout.js index c90540c76bf0..b203eae6e31d 100644 --- a/src/layout/DefaultLayout.js +++ b/src/layout/DefaultLayout.js @@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux' import { Outlet } from 'react-router-dom' import { CContainer } from '@coreui/react' import { toggleSwitcher } from '../store/features/switcher' -import useKeyboardShortcut from '../hooks/useKeyboardShortcut' +import { useHotkeys } from 'react-hotkeys-hook' import FastSwitcher from '../components/FastSwitcher' const DefaultLayout = () => { @@ -21,8 +21,22 @@ const DefaultLayout = () => { dispatch(toggleSwitcher()) }, [dispatch]) - useKeyboardShortcut(['Control', 'K'], handleFastSwitcher, { overrideSystem: true }) - useKeyboardShortcut(['Meta', 'K'], handleFastSwitcher) + useHotkeys( + 'ctrl+k', + (event) => { + handleFastSwitcher() + event.preventDefault() + }, + { filterPreventDefault: false }, + ) + useHotkeys( + 'cmd+k', + (event) => { + handleFastSwitcher() + event.preventDefault() + }, + { filterPreventDefault: false }, + ) return (
diff --git a/src/views/home/Home.js b/src/views/home/Home.js index 3a4a0057d58c..06056fba15b7 100644 --- a/src/views/home/Home.js +++ b/src/views/home/Home.js @@ -21,8 +21,8 @@ const Home = () => { return (

Dashboard

- - + + Quick Create @@ -50,7 +50,7 @@ const Home = () => { - + diff --git a/src/views/tenant/administration/ConditionalAccess.js b/src/views/tenant/administration/ConditionalAccess.js index ca4858ea435e..ac8a4132dd41 100644 --- a/src/views/tenant/administration/ConditionalAccess.js +++ b/src/views/tenant/administration/ConditionalAccess.js @@ -1,6 +1,6 @@ import React from 'react' import { useSelector } from 'react-redux' -import { CippPageList } from '../../../components' +import { CippPageList } from 'src/components' const columns = [ { name: 'Name',