ohif-viewer/platform/viewer/src/components/UserPreferences/HotkeysPreferences.js

202 lines
6.0 KiB
JavaScript
Raw Normal View History

fix: Combined Hotkeys for special characters (#1233) * fix: Combined Hotkeys for special characters * add record method to hotkey manager * fix record plugin * remove unused component * add record to modal props * rename record method * replace handlers to use hotkeyRecord * fix combined keys * change expected result count from 18 to 17 * autoformat * Remove duplicate test, that was testing the wrong things; fix label; update configs * Revert "Remove duplicate test, that was testing the wrong things; fix label; update configs" This reverts commit 4292f4fe67351962d61cae623b920dcbd87dd71d. * Fix the record plugin's registration * fix exposed record method usage * adding logging for info level items * Hotkey definitions don't need to be globally reactive; use localstorage/appconfig as sources of truth; not redux * Tidy up test * Remove unused code from UserPreferencesForm * Log info when we run a command * fix hotkey preference restore * use application configured hotkeys if there are no user preferred * Avoid logging circular ref * Fix callouts * Fix small issue with array * Fix langua issue after refactor and merge * Refactor on recordCurrentCombo as Rodrigo did before * Separating components in 2 files * WIP Refactor to simplify the user preferences and move into each form the save and controll functionalities * Remove context * Remove unused import * Initial work on Field treatment * Refactor General preferences * Small refactor removing type from HotkeyField * small update on style * Refactor and layout fixed * Make hotkeys preferences working with old hotkeys row * Move error handling out of hotkey row/input component * WIP custom form * Moving validation function to component * Exposing hotkeyRecord as it does not depend on HotkeyManager Class * Making hotkeyField as much detached possible from parent component * Small refactors * Refactor on user preferences * Clean up into the changes * Small fix to let save working * Style finish * move about docs into about folder * Fix double tap on single keys * Style refactor * Remove log * Fix log issues on unit tests * Fix unit test breaking on ohif/core index * Fixing hotkeys unpause unit test issue * Rename file to adopt lowercase * Rename file to adopt lowercase * Fixing callouts * Big refactor miving some of the components into viewer and creating small components into ohif/ui * Typo on folder name * Updating ohif ui docs * Remove comments * Fix binding of combo keys * Fix some cypress tests failures * Fixing onCancel button * Fixing e2e tests * Small style update * Fixing unit tests failing after fix issue * Remove some not used code * Remove left over after debug * Adding prevent default on hotkeys events * Fixinf existing hotkeys validator with 3 keys pressed * Exposing hotkeys as root level on ohif-core * Clean up * Exposing all availableLanguages with labels and fixing an issue on language switcher * Fixing e2e cypress tests * Preveinting some simple errors * Treating error once we try to set hotkey definitions * Adding ui notification on setHotkeys errors * Implementing a service queue request to hold until functions are implemented * Making sure toFixed is only called on Numbers Co-authored-by: Danny Brown <danny.ri.brown@gmail.com> Co-authored-by: Gustavo André Lelis <galelis@gmail.com>
2020-02-12 21:35:04 +01:00
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useSnackbarContext, TabFooter, HotkeyField } from '@ohif/ui';
import { useTranslation } from 'react-i18next';
import { hotkeysValidators } from './hotkeysValidators';
import { MODIFIER_KEYS } from './hotkeysConfig';
import { hotkeysManager } from '../../App';
import './HotkeysPreferences.styl';
/**
* Take hotkeyDefenintions and build an initialState to be used into the component state
*
* @param {Object} hotkeyDefinitions
* @returns {Object} initialState
*/
const initialState = hotkeyDefinitions => ({
hotkeys: { ...hotkeyDefinitions },
errors: {},
});
/**
* Take the updated command and keys and validate the changes with all validators
*
* @param {Object} arguments
* @param {string} arguments.commandName command name string to be updated
* @param {array} arguments.pressedKeys new array of keys to be added for the commandName
* @param {array} arguments.hotkeys all hotkeys currently into the app
* @returns {Object} {errorMessage} errorMessage coming from any of the validator or undefined if none
*/
const validateCommandKey = ({ commandName, pressedKeys, hotkeys }) => {
for (const validator of hotkeysValidators) {
const validation = validator({
commandName,
pressedKeys,
hotkeys,
});
if (validation && validation.hasError) {
return validation;
}
}
return {
errorMessage: undefined,
};
};
/**
* Take all hotkeys and split the list into two lists
*
* @param {array} hotkeys list of all hotkeys
* @returns {array} array containing two arrays of keys
*/
const splitHotkeys = hotkeys => {
const splitedHotkeys = [];
const arrayHotkeys = Object.entries(hotkeys);
if (arrayHotkeys.length) {
const halfwayThrough = Math.ceil(arrayHotkeys.length / 2);
splitedHotkeys.push(arrayHotkeys.slice(0, halfwayThrough));
splitedHotkeys.push(
arrayHotkeys.slice(halfwayThrough, arrayHotkeys.length)
);
}
return splitedHotkeys;
};
/**
* HotkeysPreferences tab
* It renders all hotkeys displayed into columns/rows
*
* It stores current state and whenever it changes, component messages parent of new value (through function callback)
* @param {object} props component props
* @param {string} props.onClose
*/
function HotkeysPreferences({ onClose }) {
const { t } = useTranslation('UserPreferencesModal');
const { hotkeyDefaults, hotkeyDefinitions } = hotkeysManager;
const [state, setState] = useState(initialState(hotkeyDefinitions));
const snackbar = useSnackbarContext();
const onResetPreferences = () => {
const defaultHotKeyDefinitions = {};
hotkeyDefaults.map(item => {
const { commandName, ...values } = item;
defaultHotKeyDefinitions[commandName] = { ...values };
});
setState(initialState(defaultHotKeyDefinitions));
};
const onSave = () => {
const { hotkeys } = state;
hotkeysManager.setHotkeys(hotkeys);
localStorage.setItem('hotkey-definitions', JSON.stringify(hotkeys));
onClose();
snackbar.show({
message: t('SaveMessage'),
type: 'success',
});
};
const onHotkeyChanged = (commandName, hotkeyDefinition, keys) => {
const { errorMessage } = validateCommandKey({
commandName,
pressedKeys: keys,
hotkeys: state.hotkeys,
});
setState(prevState => ({
hotkeys: {
...prevState.hotkeys,
[commandName]: { ...hotkeyDefinition, keys },
},
errors: {
...prevState.errors,
[commandName]: errorMessage,
},
}));
};
const hasErrors = Object.keys(state.errors).some(key => !!state.errors[key]);
const hasHotkeys = Object.keys(state.hotkeys).length;
const splitedHotkeys = splitHotkeys(state.hotkeys);
return (
<React.Fragment>
<div className="HotkeysPreferences">
{hasHotkeys ? (
<div className="hotkeyTable">
{splitedHotkeys.map((hotkeys, index) => {
return (
<div className="hotkeyColumn" key={index}>
<div className="hotkeyHeader">
<div className="headerItemText text-right">Function</div>
<div className="headerItemText text-center">Shortcut</div>
</div>
{hotkeys.map(hotkey => {
const commandName = hotkey[0];
const hotkeyDefinition = hotkey[1];
const { keys, label } = hotkeyDefinition;
const errorMessage = state.errors[hotkey[0]];
const handleChange = keys => {
onHotkeyChanged(commandName, hotkeyDefinition, keys);
};
return (
<div key={commandName} className="hotkeyRow">
<div className="hotkeyLabel">{label}</div>
<div
data-key="defaultTool"
className={classnames(
'wrapperHotkeyInput',
errorMessage ? 'stateError' : ''
)}
>
<HotkeyField
keys={keys}
modifier_keys={MODIFIER_KEYS}
handleChange={handleChange}
classNames={'hotkeyInput'}
></HotkeyField>
<span className="errorMessage">{errorMessage}</span>
</div>
</div>
);
})}
</div>
);
})}
</div>
) : (
'Hotkeys definitions is empty'
)}
</div>
<TabFooter
onResetPreferences={onResetPreferences}
onSave={onSave}
onCancel={onClose}
hasErrors={hasErrors}
t={t}
/>
</React.Fragment>
);
}
HotkeysPreferences.propTypes = {
onClose: PropTypes.func,
};
export { HotkeysPreferences };