feat: 🎸 Update hotkeys and user preferences modal (#1135)

* feat: 🎸 Update hotkeys and user preferences modal

This feature fix incompatibility with existent hotkeys component and
adds user preferences modal back

Closes: #923

* Update preferences structure in store

* Hide window level section of user preferences

* Update modal to reflect current hotkey value

* Clone object with hotkeys before passing to manager

* CR Update: Extract hotkeys manager format code to manager

* Fix broken cypress test

* Use new modal provider

* Rename hotkeyDefinitions in hotkeyspreferences and use array as representation

* Update study test and remove unused styles
This commit is contained in:
Igor Octaviano 2019-11-11 23:03:36 -03:00 committed by Danny Brown
parent dc6e9d6bb5
commit e62f5f8dd2
26 changed files with 263 additions and 256 deletions

View File

@ -1,3 +1,4 @@
import cloneDeep from 'lodash.clonedeep';
import hotkeys from './hotkeys'; import hotkeys from './hotkeys';
import log from './../log.js'; import log from './../log.js';
@ -51,10 +52,11 @@ export class HotkeysManager {
* @param {Boolean} [isDefaultDefinitions] * @param {Boolean} [isDefaultDefinitions]
*/ */
setHotkeys(hotkeyDefinitions, isDefaultDefinitions = false) { setHotkeys(hotkeyDefinitions, isDefaultDefinitions = false) {
hotkeyDefinitions.forEach(definition => this.registerHotkeys(definition)); const definitions = cloneDeep(hotkeyDefinitions);
definitions.forEach(definition => this.registerHotkeys(definition));
if (isDefaultDefinitions) { if (isDefaultDefinitions) {
this.hotkeyDefaults = hotkeyDefinitions; this.hotkeyDefaults = definitions;
} }
} }

View File

@ -1,18 +1,15 @@
import cloneDeep from 'lodash.clonedeep'; import cloneDeep from 'lodash.clonedeep';
const defaultState = { const defaultState = {
// Top level key // First tab
viewer: { hotkeyDefinitions: [
// First tab // commandName, label, keys
hotKeysData: { // [{ zoom: { label: 'Zoom', keys: ['z'] }}]
// hotkeyName, label, keys, column ],
// zoom: { label: 'Zoom', command: 'Z', column: 0 }, // Second tab
}, windowLevelData: {
// Second tab // order, description, window (int), level (int)
windowLevelData: { // 0: { description: 'Soft tissue', window: '', level: '' },
// order, description, window (int), level (int)
// 0: { description: 'Soft tissue', window: '', level: '' },
},
}, },
}; };

View File

@ -6,8 +6,8 @@ import { TableList, TableListItem } from './tableList';
import { import {
AboutContent, AboutContent,
UserPreferences, UserPreferences,
UserPreferencesModal, UserPreferencesForm,
} from './userPreferencesModal'; } from './userPreferencesForm';
import { Checkbox } from './checkbox'; import { Checkbox } from './checkbox';
import { CineDialog } from './cineDialog'; import { CineDialog } from './cineDialog';
@ -52,6 +52,6 @@ export {
Tooltip, Tooltip,
AboutContent, AboutContent,
UserPreferences, UserPreferences,
UserPreferencesModal, UserPreferencesForm,
OHIFModal, OHIFModal,
}; };

View File

@ -10,31 +10,14 @@ import PropTypes from 'prop-types';
export class HotKeysPreferences extends Component { export class HotKeysPreferences extends Component {
static propTypes = { static propTypes = {
hotKeysData: PropTypes.objectOf( hotkeyDefinitions: PropTypes.array.isRequired,
PropTypes.shape({
keys: PropTypes.arrayOf(PropTypes.string).isRequired,
label: PropTypes.string.isRequired,
})
).isRequired,
onChange: PropTypes.func,
}; };
constructor(props) { constructor(props) {
super(props); super(props);
const hotkeyCommands = Object.keys(this.props.hotKeysData);
const localHotKeys = hotkeyCommands.map(commandName => {
const definition = this.props.hotKeysData[commandName];
return {
commandName,
keys: definition.keys,
label: definition.label,
};
});
this.state = { this.state = {
hotKeys: localHotKeys, hotKeys: this.props.hotkeyDefinitions,
errorMessages: {}, errorMessages: {},
}; };
@ -53,24 +36,28 @@ export class HotKeysPreferences extends Component {
const { ctrlKey, altKey, shiftKey } = keyDownEvent; const { ctrlKey, altKey, shiftKey } = keyDownEvent;
if (ctrlKey && !altKey) { if (ctrlKey && !altKey) {
keysPressedArray.push('CTRL'); keysPressedArray.push('ctrl');
} }
if (shiftKey && !altKey) { if (shiftKey && !altKey) {
keysPressedArray.push('SHIFT'); keysPressedArray.push('shift');
} }
if (altKey && !ctrlKey) { if (altKey && !ctrlKey) {
keysPressedArray.push('ALT'); keysPressedArray.push('alt');
} }
return keysPressedArray; return keysPressedArray;
} }
getConflictingCommand(currentToolKey, hotKeyCommand) { getConflictingCommand(currentCommandName, currentHotKeys) {
return Object.keys(this.state.hotKeys).find(tool => { return this.state.hotKeys.find((tool, index) => {
const value = this.state.hotKeys[tool].command; const toolHotKeys = tool.keys[0];
return value && value === hotKeyCommand && tool !== currentToolKey; return (
toolHotKeys &&
toolHotKeys === currentHotKeys &&
tool.commandName !== currentCommandName
);
}); });
} }
@ -89,7 +76,7 @@ export class HotKeysPreferences extends Component {
specialKeyName || specialKeyName ||
keyDownEvent.key || keyDownEvent.key ||
String.fromCharCode(keyDownEvent.keyCode); String.fromCharCode(keyDownEvent.keyCode);
pressedKeys.push(keyName.toUpperCase()); pressedKeys.push(keyName);
} }
this.updateHotKeysState(commandName, pressedKeys.join('+')); this.updateHotKeysState(commandName, pressedKeys.join('+'));
@ -136,17 +123,17 @@ export class HotKeysPreferences extends Component {
const hotKey = this.state.hotKeys[hotKeyIndex]; const hotKey = this.state.hotKeys[hotKeyIndex];
const keys = hotKey.keys[0]; const keys = hotKey.keys[0];
const pressedKeys = keys.split('+'); const pressedKeys = keys.split('+');
const lastPressedKey = pressedKeys[pressedKeys.length - 1].toUpperCase(); const lastPressedKey = pressedKeys[pressedKeys.length - 1];
// clear the prior errors // clear the prior errors
this.setState({ errorMessages: {} }, () => { this.setState({ errorMessages: {} }, () => {
// Check if it has a valid modifier // Check if it has a valid modifier
const isModifier = ['CTRL', 'ALT', 'SHIFT'].includes(lastPressedKey); const isModifier = ['ctrl', 'alt', 'shift'].includes(lastPressedKey);
if (isModifier) { if (isModifier) {
this.updateHotKeysState(commandName, ''); this.updateHotKeysState(commandName, '');
this.updateErrorsState( this.updateErrorsState(
commandName, commandName,
"It's not possible to define only modifier keys (CTRL, ALT and SHIFT) as a shortcut" "It's not possible to define only modifier keys (ctrl, alt and shift) as a shortcut"
); );
return; return;
} }
@ -154,21 +141,13 @@ export class HotKeysPreferences extends Component {
/* /*
* Check if it has some conflict * Check if it has some conflict
*/ */
const conflictedCommandKey = this.getConflictingCommand( const conflictedCommand = this.getConflictingCommand(commandName, keys);
commandName, if (conflictedCommand) {
keys this.updateHotKeysState(commandName, '');
);
if (conflictedCommandKey) {
const conflictedCommand = this.state.hotKeys[conflictedCommandKey];
this.updateErrorsState( this.updateErrorsState(
commandName, commandName,
`"${conflictedCommand.label}" is already using the "${ `"${conflictedCommand.label}" is already using the "${keys}" shortcut.`
conflictedCommand.command
}" shortcut.`
); );
this.updateErrorsState(conflictedCommandKey, '');
this.updateHotKeysState(commandName, '');
return; return;
} }
@ -177,8 +156,7 @@ export class HotKeysPreferences extends Component {
*/ */
const modifierCommand = pressedKeys const modifierCommand = pressedKeys
.slice(0, pressedKeys.length - 1) .slice(0, pressedKeys.length - 1)
.join('+') .join('+');
.toUpperCase();
const disallowedCombination = disallowedCombinations[modifierCommand]; const disallowedCombination = disallowedCombinations[modifierCommand];
const hasDisallowedCombinations = disallowedCombination const hasDisallowedCombinations = disallowedCombination
@ -189,7 +167,7 @@ export class HotKeysPreferences extends Component {
this.updateHotKeysState(commandName, ''); this.updateHotKeysState(commandName, '');
this.updateErrorsState( this.updateErrorsState(
commandName, commandName,
"It's not possible to define only modifier keys (CTRL, ALT and SHIFT) as a shortcut" `"${pressedKeys.join('+')}" shortcut combination is not allowed`
); );
return; return;
} }

View File

@ -8,14 +8,14 @@ import './UserPreferences.styl';
export class UserPreferences extends Component { export class UserPreferences extends Component {
static defaultProps = { static defaultProps = {
hotKeysData: {}, hotkeyDefinitions: [],
windowLevelData: {}, windowLevelData: {},
generalData: {}, generalData: {},
}; };
// TODO: Make this more generic. Tabs should not be restricted to these entries // TODO: Make this more generic. Tabs should not be restricted to these entries
static propTypes = { static propTypes = {
hotKeysData: PropTypes.object.isRequired, hotkeyDefinitions: PropTypes.array.isRequired,
windowLevelData: PropTypes.object.isRequired, windowLevelData: PropTypes.object.isRequired,
generalData: PropTypes.object.isRequired, generalData: PropTypes.object.isRequired,
}; };
@ -32,7 +32,9 @@ export class UserPreferences extends Component {
return ( return (
<form className="form-themed themed"> <form className="form-themed themed">
<div className="form-content"> <div className="form-content">
<HotKeysPreferences hotKeysData={this.props.hotKeysData} /> <HotKeysPreferences
hotkeyDefinitions={this.props.hotkeyDefinitions}
/>
</div> </div>
</form> </form>
); );
@ -66,8 +68,8 @@ export class UserPreferences extends Component {
switch (tabIndex) { switch (tabIndex) {
case 0: case 0:
return this.renderHotkeysTab(); return this.renderHotkeysTab();
case 1: /* case 1:
return this.renderWindowLevelTab(); return this.renderWindowLevelTab(); */
case 2: case 2:
return this.renderGeneralTab(); return this.renderGeneralTab();
@ -93,14 +95,16 @@ export class UserPreferences extends Component {
> >
<button>Hotkeys</button> <button>Hotkeys</button>
</li> </li>
<li {false && (
onClick={() => { <li
this.tabClick(1); onClick={() => {
}} this.tabClick(1);
className={this.getTabClass(1)} }}
> className={this.getTabClass(1)}
<button>Window Level</button> >
</li> <button>Window Level</button>
</li>
)}
<li <li
onClick={() => { onClick={() => {
this.tabClick(2); this.tabClick(2);

View File

@ -0,0 +1,86 @@
import './UserPreferencesForm.styl';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from '../../utils/LanguageProvider';
import cloneDeep from 'lodash.clonedeep';
import isEqual from 'lodash.isequal';
import { UserPreferences } from './UserPreferences';
class UserPreferencesForm extends Component {
// TODO: Make this component more generic to allow things other than W/L and hotkeys...
static propTypes = {
onClose: PropTypes.func,
onSave: PropTypes.func,
onResetToDefaults: PropTypes.func,
windowLevelData: PropTypes.object,
hotkeyDefinitions: PropTypes.array,
t: PropTypes.func,
};
constructor(props) {
super(props);
this.state = {
windowLevelData: cloneDeep(props.windowLevelData),
hotkeyDefinitions: cloneDeep(props.hotkeyDefinitions),
};
}
save = () => {
this.props.onSave({
windowLevelData: this.state.windowLevelData,
hotkeyDefinitions: this.state.hotkeyDefinitions,
});
};
componentDidUpdate(prev, next) {
const newStateData = {};
if (!isEqual(prev.windowLevelData, next.windowLevelData)) {
newStateData.windowLevelData = prev.windowLevelData;
}
if (!isEqual(prev.hotkeyDefinitions, next.hotkeyDefinitions)) {
newStateData.hotkeyDefinitions = prev.hotkeyDefinitions;
}
if (newStateData.hotkeyDefinitions || newStateData.windowLevelData) {
this.setState(newStateData);
}
}
render() {
return (
<div className="UserPreferencesForm">
<UserPreferences
windowLevelData={this.state.windowLevelData}
hotkeyDefinitions={this.state.hotkeyDefinitions}
/>
<div className="footer">
<button
className="btn btn-danger pull-left"
onClick={this.props.onResetToDefaults}
>
{this.props.t('Reset to Defaults')}
</button>
<div>
<div onClick={this.props.onClose} className="btn btn-default">
{this.props.t('Cancel')}
</div>
<button className="btn btn-primary" onClick={this.save}>
{this.props.t('Save')}
</button>
</div>
</div>
</div>
);
}
}
const connectedComponent = withTranslation('UserPreferencesForm')(
UserPreferencesForm
);
export { connectedComponent as UserPreferencesForm };
export default connectedComponent;

View File

@ -12,6 +12,13 @@
text-shadow: 0 1px 0 #fff; text-shadow: 0 1px 0 #fff;
opacity: .2; opacity: .2;
.ModalHeader .UserPreferencesForm
ol, ul .footer
margin-top: 0; display: flex
flex-direction: row
padding-bottom: 20px
justify-content: space-between
div
button:last-child
margin-left: 10px

View File

@ -1,18 +1,18 @@
--- ---
name: User Preferences Modal name: User Preferences Form
menu: Components menu: Components
route: /components/user-preferences-modal route: /components/user-preferences-form
--- ---
import { Playground, Props } from 'docz' import { Playground, Props } from 'docz'
import { State } from 'react-powerplug' import { State } from 'react-powerplug'
import { UserPreferencesModal } from './../index.js' import { UserPreferencesForm } from './../index.js'
import NameSpace from '../../../__docs__/NameSpace' import NameSpace from '../../../__docs__/NameSpace'
// //
import windowLevelDefaults from './windowLevelDefaults.js' import windowLevelDefaults from './windowLevelDefaults.js'
import hotkeyDefaults from './hotkeyDefaults.js' import hotkeyDefaults from './hotkeyDefaults.js'
# User Preferences Modal # User Preferences Form
## Basic usage ## Basic usage
@ -20,7 +20,7 @@ import hotkeyDefaults from './hotkeyDefaults.js'
<State initial={{ <State initial={{
isOpen: false, isOpen: false,
windowLevelData: windowLevelDefaults, windowLevelData: windowLevelDefaults,
hotKeysData: hotkeyDefaults, hotkeyDefinitions: hotkeyDefaults,
}}> }}>
{({ state, setState }) => ( {({ state, setState }) => (
@ -32,7 +32,7 @@ import hotkeyDefaults from './hotkeyDefaults.js'
> >
Open user preferences Open user preferences
</button> </button>
<UserPreferencesModal <UserPreferencesForm
{...state} {...state}
onCancel={() => setState({ isOpen: false })} onCancel={() => setState({ isOpen: false })}
onSave={() => alert('on save')} onSave={() => alert('on save')}
@ -47,8 +47,8 @@ import hotkeyDefaults from './hotkeyDefaults.js'
## API ## API
<Props of={UserPreferencesModal} /> <Props of={UserPreferencesForm} />
## Translation Namespace ## Translation Namespace
<NameSpace name="UserPreferencesModal" /> <NameSpace name="UserPreferencesForm" />

View File

@ -4,38 +4,38 @@ const range = (start, end) => {
export const disallowedCombinations = { export const disallowedCombinations = {
'': [], '': [],
ALT: ['SPACE'], alt: ['space'],
SHIFT: [], shift: [],
CTRL: [ ctrl: [
'F4', 'f4',
'F5', 'f5',
'F11', 'f11',
'W', 'w',
'R', 'r',
'T', 't',
'O', 'o',
'P', 'p',
'A', 'a',
'D', 'd',
'F', 'f',
'G', 'g',
'H', 'h',
'J', 'j',
'L', 'l',
'Z', 'z',
'X', 'x',
'C', 'c',
'V', 'v',
'B', 'b',
'N', 'n',
'PAGEDOWN', 'pagedown',
'PAGEUP', 'pageup',
], ],
'CTRL+SHIFT': ['Q', 'W', 'R', 'T', 'P', 'A', 'H', 'V', 'B', 'N'], 'ctrl+shift': ['q', 'w', 'r', 't', 'p', 'a', 'h', 'v', 'b', 'n'],
}; };
export const allowedKeys = [ export const allowedKeys = [
...[8, 13, 27, 32, 46], // BACKSPACE, ENTER, ESCAPE, SPACE, DELETE ...[8, 13, 27, 32, 46], // backspace, enter, escape, space, delete
...[12, 106, 107, 109, 110, 111], // Numpad keys ...[12, 106, 107, 109, 110, 111], // Numpad keys
...range(218, 220), // [\] ...range(218, 220), // [\]
...range(185, 190), // ;=,-./ ...range(185, 190), // ;=,-./

View File

@ -1,4 +1,4 @@
export { UserPreferences } from './UserPreferences.js'; export { UserPreferences } from './UserPreferences.js';
export { AboutContent } from '../content/aboutContent/AboutContent.js'; export { AboutContent } from '../content/aboutContent/AboutContent.js';
export { UserPreferencesModal } from './UserPreferencesModal.js'; export { UserPreferencesForm } from './UserPreferencesForm.js';
export { GeneralPreferences } from './GeneralPreferences.js'; export { GeneralPreferences } from './GeneralPreferences.js';

View File

@ -1,107 +0,0 @@
import './UserPreferencesModal.styl';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Modal from 'react-bootstrap-modal';
import { withTranslation } from '../../utils/LanguageProvider';
import 'react-bootstrap-modal/lib/css/rbm-patch.css';
import cloneDeep from 'lodash.clonedeep';
import isEqual from 'lodash.isequal';
import { UserPreferences } from './UserPreferences';
// TODO: Is this the only component importing these?
import './../../design/styles/common/modal.styl';
class UserPreferencesModal extends Component {
// TODO: Make this component more generic to allow things other than W/L and hotkeys...
static propTypes = {
isOpen: PropTypes.bool.isRequired,
onCancel: PropTypes.func,
onSave: PropTypes.func,
onResetToDefaults: PropTypes.func,
windowLevelData: PropTypes.object,
hotKeysData: PropTypes.object,
t: PropTypes.func,
};
constructor(props) {
super(props);
this.state = {
windowLevelData: cloneDeep(props.windowLevelData),
hotKeysData: cloneDeep(props.hotKeysData),
};
}
static defaultProps = {
isOpen: false,
};
save = () => {
this.props.onSave({
windowLevelData: this.state.windowLevelData,
hotKeysData: this.state.hotKeysData,
});
};
componentDidUpdate(prev, next) {
const newStateData = {};
if (!isEqual(prev.windowLevelData, next.windowLevelData)) {
newStateData.windowLevelData = prev.windowLevelData;
}
if (!isEqual(prev.hotKeysData, next.hotKeysData)) {
newStateData.hotKeysData = prev.hotKeysData;
}
if (newStateData.hotKeysData || newStateData.windowLevelData) {
this.setState(newStateData);
}
}
render() {
return (
<Modal
show={this.props.isOpen}
onHide={this.props.onCancel}
aria-labelledby="ModalHeader"
className="ModalHeader modal fade themed in"
backdrop={false}
large={true}
keyboard={false}
>
<Modal.Header closeButton>
<Modal.Title>{this.props.t('User Preferences')}</Modal.Title>
</Modal.Header>
<Modal.Body>
<UserPreferences
windowLevelData={this.state.windowLevelData}
hotKeysData={this.state.hotKeysData}
/>
</Modal.Body>
<Modal.Footer>
<button
className="btn btn-danger pull-left"
onClick={this.props.onResetToDefaults}
>
{this.props.t('Reset to Defaults')}
</button>
<Modal.Dismiss className="btn btn-default">
{this.props.t('Cancel')}
</Modal.Dismiss>
<button className="btn btn-primary" onClick={this.save}>
{this.props.t('Save')}
</button>
</Modal.Footer>
</Modal>
);
}
}
const connectedComponent = withTranslation('UserPreferencesModal')(
UserPreferencesModal
);
export { connectedComponent as UserPreferencesModal };
export default connectedComponent;

View File

@ -24,7 +24,7 @@ import {
Tooltip, Tooltip,
AboutContent, AboutContent,
UserPreferences, UserPreferences,
UserPreferencesModal, UserPreferencesForm,
OHIFModal, OHIFModal,
} from './components'; } from './components';
import { useDebounce, useMedia } from './hooks'; import { useDebounce, useMedia } from './hooks';
@ -101,7 +101,7 @@ export {
Tooltip, Tooltip,
AboutContent, AboutContent,
UserPreferences, UserPreferences,
UserPreferencesModal, UserPreferencesForm,
ViewerbaseDragDropContext, ViewerbaseDragDropContext,
SnackbarProvider, SnackbarProvider,
useSnackbarContext, useSnackbarContext,

View File

@ -267,8 +267,12 @@ describe('OHIF Study Viewer Page', function() {
}); });
it('opens About modal and verify the displayed information', function() { it('opens About modal and verify the displayed information', function() {
cy.get('[data-cy="options-menu"]').click(); cy.get('[data-cy="options-menu"]')
cy.get('[data-cy="about-item-menu"]').click(); .first()
.click();
cy.get('[data-cy="about-item-menu"]')
.first()
.click();
cy.get('.modal-content') cy.get('.modal-content')
.as('aboutOverlay') .as('aboutOverlay')
.should('be.visible'); .should('be.visible');

View File

@ -4,6 +4,10 @@
height: var(--top-bar-height); height: var(--top-bar-height);
} }
.dd-item {
width: 100%;
}
/* Home Page */ /* Home Page */
.entry-header.header-big { .entry-header.header-big {
background: rgba(21, 25, 30, 0.7); background: rgba(21, 25, 30, 0.7);

View File

@ -3,13 +3,11 @@ import { Link, withRouter } from 'react-router-dom';
import { withTranslation } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Dropdown } from '@ohif/ui'; import ConnectedUserPreferencesForm from '../../connectedComponents/ConnectedUserPreferencesForm';
import { AboutContent } from '@ohif/ui'; import { Dropdown, AboutContent, withModal } from '@ohif/ui';
import { withModal } from '@ohif/ui';
import OHIFLogo from '../OHIFLogo/OHIFLogo.js'; import OHIFLogo from '../OHIFLogo/OHIFLogo.js';
import { hotkeysManager } from './../../App.js';
import './Header.css'; import './Header.css';
// Context // Context
import AppContext from './../../context/AppContext'; import AppContext from './../../context/AppContext';
@ -30,23 +28,9 @@ class Header extends Component {
children: OHIFLogo(), children: OHIFLogo(),
}; };
// onSave: data => {
// const contextName = store.getState().commandContext.context;
// const preferences = cloneDeep(store.getState().preferences);
// preferences[contextName] = data;
// dispatch(setUserPreferences(preferences));
// dispatch(setUserPreferencesModalOpen(false));
// OHIF.hotkeysUtil.setHotkeys(data.hotKeysData);
// },
// onResetToDefaults: () => {
// dispatch(setUserPreferences());
// dispatch(setUserPreferencesModalOpen(false));
// OHIF.hotkeysUtil.setHotkeys();
// },
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { isUserPreferencesOpen: false, isOpen: false }; this.state = { isOpen: false };
this.loadOptions(); this.loadOptions();
} }
@ -68,6 +52,16 @@ class Header extends Component {
customClassName: 'AboutContent', customClassName: 'AboutContent',
}), }),
}, },
{
title: 'Preferences ',
icon: {
name: 'user',
},
onClick: () =>
show(ConnectedUserPreferencesForm, {
title: t('User Preferences'),
}),
},
]; ];
if (user && userManager) { if (user && userManager) {
@ -77,15 +71,6 @@ class Header extends Component {
onClick: () => userManager.signoutRedirect(), onClick: () => userManager.signoutRedirect(),
}); });
} }
this.hotKeysData = hotkeysManager.hotkeyDefinitions;
}
onUserPreferencesSave({ windowLevelData, hotKeysData }) {
// console.log(windowLevelData);
// console.log(hotKeysData);
// TODO: Update hotkeysManager
// TODO: reset `this.hotKeysData`
} }
// ANTD -- Hamburger, Drawer, Menu // ANTD -- Hamburger, Drawer, Menu

View File

@ -1,10 +1,16 @@
import Header from '../components/Header/Header.js'; import Header from '../components/Header/Header.js';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { hotkeysManager } from '../App.js';
const mapStateToProps = state => { const mapStateToProps = state => {
const hotkeyDefinitions =
state.preferences.hotkeyDefinitions.length > 0
? state.preferences.hotkeyDefinitions
: hotkeysManager.hotkeyDefaults;
hotkeysManager.setHotkeys(hotkeyDefinitions);
return { return {
user: state.oidc && state.oidc.user, user: state.oidc && state.oidc.user,
isOpen: state.ui.userPreferencesModalOpen,
}; };
}; };

View File

@ -0,0 +1,41 @@
import { connect } from 'react-redux';
import { UserPreferencesForm } from '@ohif/ui';
import OHIF from '@ohif/core';
import { hotkeysManager } from '../App.js';
const { setUserPreferences } = OHIF.redux.actions;
const mapStateToProps = (state, ownProps) => {
const hotkeyDefinitions =
state.preferences.hotkeyDefinitions.length > 0
? state.preferences.hotkeyDefinitions
: hotkeysManager.hotkeyDefaults;
hotkeysManager.setHotkeys(hotkeyDefinitions);
return {
onClose: ownProps.hide,
windowLevelData: state.preferences ? state.preferences.windowLevelData : {},
hotkeyDefinitions,
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onSave: ({ windowLevelData, hotkeyDefinitions }) => {
hotkeysManager.setHotkeys(hotkeyDefinitions);
ownProps.hide();
dispatch(setUserPreferences({ windowLevelData, hotkeyDefinitions }));
},
onResetToDefaults: () => {
hotkeysManager.restoreDefaultBindings();
ownProps.hide();
dispatch(setUserPreferences());
},
};
};
const ConnectedUserPreferencesForm = connect(
mapStateToProps,
mapDispatchToProps
)(UserPreferencesForm);
export default ConnectedUserPreferencesForm;