diff --git a/package-lock.json b/package-lock.json index d8b43b190f..72f85d4c04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "react-chartjs-2": "^5.2.0", "react-datepicker": "^4.25.0", "react-dom": "^17.0.2", - "react-hotkeys": "^2.0.0", + "react-hotkeys-hook": "^4.4.4", "react-i18next": "^14.0.1", "react-icons": "^5.2.1", "react-redux": "^7.2.9", @@ -19212,15 +19212,13 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" }, - "node_modules/react-hotkeys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", - "integrity": "sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q==", - "dependencies": { - "prop-types": "^15.6.1" - }, + "node_modules/react-hotkeys-hook": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz", + "integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==", "peerDependencies": { - "react": ">= 0.14.0" + "react": ">=16.8.1", + "react-dom": ">=16.8.1" } }, "node_modules/react-i18next": { diff --git a/package.json b/package.json index 5091828d17..fc8365f5d2 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "react-chartjs-2": "^5.2.0", "react-datepicker": "^4.25.0", "react-dom": "^17.0.2", - "react-hotkeys": "^2.0.0", + "react-hotkeys-hook": "^4.4.4", "react-i18next": "^14.0.1", "react-icons": "^5.2.1", "react-redux": "^7.2.9", diff --git a/src/components/Header.tsx b/src/components/Header.tsx index fac80f28e0..97bb147f20 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -6,7 +6,6 @@ import i18n from "../i18n/i18n"; import languages from "../i18n/languages"; // @ts-expect-error TS(2307): Cannot find module '../img/opencast-white.svg' or ... Remove this comment to see the full error message import opencastLogo from "../img/opencast-white.svg"; -import { GlobalHotKeys } from "react-hotkeys"; import { setSpecificServiceFilter } from "../thunks/tableFilterThunks"; import { loadServicesIntoTable } from "../thunks/tableThunks"; import { getErrorCount, getHealthStatus } from "../selectors/healthSelectors"; @@ -20,6 +19,7 @@ import { getCurrentLanguageInformation, hasAccess } from "../utils/utils"; import { overflowStyle } from "../utils/componentStyles"; import RegistrationModal from "./shared/RegistrationModal"; import HotKeyCheatSheet from "./shared/HotKeyCheatSheet"; +import { useHotkeys } from "react-hotkeys-hook"; import { useAppDispatch, useAppSelector } from "../store"; import { HealthStatus, fetchHealthStatus } from "../slices/healthSlice"; import { UserInfoState } from "../slices/userInfoSlice"; @@ -100,10 +100,19 @@ const Header = ({ setHotKeyCheatSheet(false); }; - const hotKeyHandlers = { - HOTKEY_CHEATSHEET: showHotKeyCheatSheet, + const toggleHotKeyCheatSheet = () => { + setHotKeyCheatSheet(!displayHotKeyCheatSheet); }; + useHotkeys( + availableHotkeys.general.HOTKEY_CHEATSHEET.sequence, + () => toggleHotKeyCheatSheet(), + { + description: t(availableHotkeys.general.HOTKEY_CHEATSHEET.description) ?? undefined + }, + [toggleHotKeyCheatSheet] + ); + useEffect(() => { // Function for handling clicks outside of an open dropdown menu const handleClickOutside = (e: MouseEvent) => { @@ -143,11 +152,6 @@ const Header = ({ return ( <> -
{/* Opencast logo in upper left corner */}
diff --git a/src/components/events/Events.tsx b/src/components/events/Events.tsx index 4293543fe3..2d9d60b00a 100644 --- a/src/components/events/Events.tsx +++ b/src/components/events/Events.tsx @@ -31,7 +31,7 @@ import Header from "../Header"; import Footer from "../Footer"; import { getUserInformation } from "../../selectors/userInfoSelectors"; import { hasAccess } from "../../utils/utils"; -import { GlobalHotKeys } from "react-hotkeys"; +import { useHotkeys } from "react-hotkeys-hook"; import { availableHotkeys } from "../../configs/hotkeysConfig"; import { getCurrentFilterResource } from "../../selectors/tableFilterSelectors"; import { fetchAssetUploadOptions } from "../../thunks/assetsThunks"; @@ -186,17 +186,17 @@ const Events = ({ setEditMetadataEventsModal(false); }; - const hotKeyHandlers = { - NEW_EVENT: showNewEventModal, - }; + useHotkeys( + availableHotkeys.general.NEW_EVENT.sequence, + () => showNewEventModal(), + { + description: t(availableHotkeys.general.NEW_EVENT.description) ?? undefined + }, + [showNewEventModal] + ); return ( <> -
diff --git a/src/components/events/Series.tsx b/src/components/events/Series.tsx index bdadb37390..58149d934c 100644 --- a/src/components/events/Series.tsx +++ b/src/components/events/Series.tsx @@ -24,8 +24,8 @@ import Footer from "../Footer"; import { getUserInformation } from "../../selectors/userInfoSelectors"; import { hasAccess } from "../../utils/utils"; import { availableHotkeys } from "../../configs/hotkeysConfig"; -import { GlobalHotKeys } from "react-hotkeys"; import { getCurrentFilterResource } from "../../selectors/tableFilterSelectors"; +import { useHotkeys } from "react-hotkeys-hook"; import { useAppDispatch, useAppSelector } from "../../store"; import { fetchEvents } from "../../slices/eventSlice"; import { @@ -158,17 +158,15 @@ const Series = ({ setDeleteSeriesModal(false); }; - const hotKeyHandlers = { - NEW_SERIES: showNewSeriesModal, - }; + useHotkeys( + availableHotkeys.general.NEW_SERIES.sequence, + () => showNewSeriesModal(), + { description: t(availableHotkeys.general.NEW_SERIES.description) ?? undefined }, + [showNewSeriesModal] + ); return ( <> -
diff --git a/src/components/shared/HotKeyCheatSheet.tsx b/src/components/shared/HotKeyCheatSheet.tsx index 1594b2d8f8..23110da2b8 100644 --- a/src/components/shared/HotKeyCheatSheet.tsx +++ b/src/components/shared/HotKeyCheatSheet.tsx @@ -1,19 +1,37 @@ import React from "react"; import { useTranslation } from "react-i18next"; import { availableHotkeys } from "../../configs/hotkeysConfig"; +import { useHotkeysContext } from "react-hotkeys-hook"; +import { Hotkey } from "react-hotkeys-hook/dist/types"; /** * This component renders the hotkey cheat sheet showing all available hotkeys */ -const HotKeyCheatSheet = ({ - close -}: any) => { +const HotKeyCheatSheet: React.FC<{ + close: () => void, +}> = ({ + close +}) => { const { t } = useTranslation(); const handleClose = () => { close(); }; + const { hotkeys } = useHotkeysContext(); + + const checkHotkeys = (hotkeys: readonly Hotkey[], searchkeys: string[]) => { + for (const hotkey of hotkeys) { + if (!hotkey.keys) { continue; } + if (hotkey.keys.length !== searchkeys.length) { continue; } + if (hotkey.keys.every((element, index) => element === searchkeys[index])) { + return true; + } + } + + return false; + } + return ( <>
@@ -38,21 +56,18 @@ const HotKeyCheatSheet = ({ {/* Repeat row for each hotkey in group*/} -{/* @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message */} {Object.keys(availableHotkeys[hotkeyGroup]).map( (hotkey, key) => ( - +

{/* repeat for each key in hotkey */} -{/* @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message */} {availableHotkeys[hotkeyGroup][ hotkey -// @ts-expect-error TS(7006): Parameter 'comboKey' implicitly has an 'any' type. - ].combo.map((comboKey, key) => ( - <> - + ].sequence.map((comboKey, key) => ( + + {t( "HOTKEYS.KEYS." + @@ -62,23 +77,20 @@ const HotKeyCheatSheet = ({ {comboKey === -// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message availableHotkeys[hotkeyGroup][hotkey] - .combo[ -// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message + .sequence[ availableHotkeys[hotkeyGroup][hotkey] - .combo.length - 1 + .sequence.length - 1 ] ? "" : " + "} - + ))}

{t( -// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message availableHotkeys[hotkeyGroup][hotkey] .description )} diff --git a/src/components/shared/MainNav.tsx b/src/components/shared/MainNav.tsx index 6735f83b00..93ffee601d 100644 --- a/src/components/shared/MainNav.tsx +++ b/src/components/shared/MainNav.tsx @@ -21,7 +21,7 @@ import { getUserInformation } from "../../selectors/userInfoSelectors"; import { hasAccess } from "../../utils/utils"; import { fetchServices } from "../../slices/serviceSlice"; import { fetchGroups } from "../../slices/groupSlice"; -import { GlobalHotKeys } from "react-hotkeys"; +import { useHotkeys } from "react-hotkeys-hook"; import { availableHotkeys } from "../../configs/hotkeysConfig"; import { fetchAcls } from "../../slices/aclSlice"; import { useAppDispatch, useAppSelector } from "../../store"; @@ -206,26 +206,29 @@ const MainNav = ({ loadingThemesIntoTable(); }; - const hotkeyLoadEvents = () => { - navigate("/events/events"); - }; - - const hotkeyLoadSeries = () => { - navigate("/events/series"); - }; + useHotkeys( + availableHotkeys.general.EVENT_VIEW.sequence, + () => navigate("/events/events"), + { description: t(availableHotkeys.general.EVENT_VIEW.description) ?? undefined }, + [] + ); + + useHotkeys( + availableHotkeys.general.SERIES_VIEW.sequence, + () => navigate("/events/series"), + { description: t(availableHotkeys.general.SERIES_VIEW.description) ?? undefined }, + [] + ); + + useHotkeys( + availableHotkeys.general.MAIN_MENU.sequence, + () => toggleMenu(), + { description: t(availableHotkeys.general.MAIN_MENU.description) ?? undefined }, + [toggleMenu] + ); - const hotKeyHandlers = { - EVENT_VIEW: hotkeyLoadEvents, - SERIES_VIEW: hotkeyLoadSeries, - MAIN_MENU: toggleMenu, - }; return ( <> -
toggleMenu()}> {isOpen && (