* WindowLevel preset code changes * Remove localStorage code as its already being saved and some small refactor on reducer/action * Creating unit tests for preferences reducer * Fix cypress after class naming change * Make hidden false as default for tab components * Remove addUserPreferences * Small refactor to use commandsManager from getCommandsModule instead of getting it from App.js
This commit is contained in:
parent
4fd0c6dfcb
commit
ebc01a8ca2
@ -242,6 +242,18 @@ const commandsModule = ({ servicesManager }) => {
|
|||||||
setCornerstoneLayout: () => {
|
setCornerstoneLayout: () => {
|
||||||
setCornerstoneLayout();
|
setCornerstoneLayout();
|
||||||
},
|
},
|
||||||
|
setWindowLevel: ({ viewports, window, level }) => {
|
||||||
|
const enabledElement = getEnabledElement(viewports.activeViewportIndex);
|
||||||
|
|
||||||
|
if (enabledElement) {
|
||||||
|
let viewport = cornerstone.getViewport(enabledElement);
|
||||||
|
viewport.voi = {
|
||||||
|
windowWidth: Number(window),
|
||||||
|
windowCenter: Number(level),
|
||||||
|
};
|
||||||
|
cornerstone.setViewport(enabledElement, viewport);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const definitions = {
|
const definitions = {
|
||||||
@ -347,6 +359,11 @@ const commandsModule = ({ servicesManager }) => {
|
|||||||
options: {},
|
options: {},
|
||||||
context: 'VIEWER',
|
context: 'VIEWER',
|
||||||
},
|
},
|
||||||
|
setWindowLevel: {
|
||||||
|
commandFn: actions.setWindowLevel,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
SET_VIEWPORT_ACTIVE,
|
SET_VIEWPORT_ACTIVE,
|
||||||
SET_VIEWPORT_LAYOUT,
|
SET_VIEWPORT_LAYOUT,
|
||||||
SET_VIEWPORT_LAYOUT_AND_DATA,
|
SET_VIEWPORT_LAYOUT_AND_DATA,
|
||||||
|
SET_USER_PREFERENCES,
|
||||||
} from './constants/ActionTypes.js';
|
} from './constants/ActionTypes.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +90,7 @@ export const clearStudyLoadingProgress = progressId => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const setUserPreferences = state => ({
|
export const setUserPreferences = state => ({
|
||||||
type: 'SET_USER_PREFERENCES',
|
type: SET_USER_PREFERENCES,
|
||||||
state,
|
state,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -20,3 +20,8 @@ export const SET_SERVERS = 'SET_SERVERS';
|
|||||||
* EXTENSIONS
|
* EXTENSIONS
|
||||||
*/
|
*/
|
||||||
export const SET_EXTENSION_DATA = 'SET_EXTENSION_DATA';
|
export const SET_EXTENSION_DATA = 'SET_EXTENSION_DATA';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PREFERENCES
|
||||||
|
* */
|
||||||
|
export const SET_USER_PREFERENCES = 'SET_USER_PREFERENCES';
|
||||||
|
|||||||
@ -1,25 +1,30 @@
|
|||||||
import cloneDeep from 'lodash.clonedeep';
|
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
windowLevelData: {
|
windowLevelData: {
|
||||||
// order, description, window (int), level (int)
|
1: { description: 'Soft tissue', window: '550', level: '40' },
|
||||||
// 0: { description: 'Soft tissue', window: '', level: '' },
|
2: { description: 'Lung', window: '150', level: '-600' },
|
||||||
|
3: { description: 'Liver', window: '150', level: '90' },
|
||||||
|
4: { description: 'Bone', window: '2500', level: '480' },
|
||||||
|
5: { description: 'Brain', window: '80', level: '40' },
|
||||||
|
6: { description: 'Trest', window: '1', level: '1' },
|
||||||
|
7: { description: '', window: '', level: '' },
|
||||||
|
8: { description: '', window: '', level: '' },
|
||||||
|
9: { description: '', window: '', level: '' },
|
||||||
|
10: { description: '', window: '', level: '' },
|
||||||
},
|
},
|
||||||
generalPreferences: {
|
generalPreferences: {
|
||||||
// language: 'en-US'
|
// language: 'en-US'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const preferences = (state, action) => {
|
const preferences = (state = defaultState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SET_USER_PREFERENCES': {
|
case 'SET_USER_PREFERENCES': {
|
||||||
const newState = action.state || cloneDeep(defaultState);
|
return Object.assign({}, state, action.state);
|
||||||
|
|
||||||
return Object.assign({}, state, newState);
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return cloneDeep(state) || cloneDeep(defaultState);
|
return state;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { defaultState };
|
||||||
export default preferences;
|
export default preferences;
|
||||||
|
|||||||
31
platform/core/src/redux/reducers/preferences.test.js
Normal file
31
platform/core/src/redux/reducers/preferences.test.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Reducer } from 'redux-testkit';
|
||||||
|
|
||||||
|
import reducer, { defaultState } from './preferences';
|
||||||
|
import { SET_USER_PREFERENCES } from './../constants/ActionTypes.js';
|
||||||
|
|
||||||
|
describe('preferences reducer', () => {
|
||||||
|
it('should return the initial state', () => {
|
||||||
|
expect(reducer(undefined, {})).toEqual(defaultState);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set user preferences state and properly merge with current state', () => {
|
||||||
|
const initialState = defaultState;
|
||||||
|
|
||||||
|
const action = {
|
||||||
|
type: SET_USER_PREFERENCES,
|
||||||
|
state: { generalPreferences: { language: 'es' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedState = {
|
||||||
|
windowLevelData: defaultState.windowLevelData,
|
||||||
|
generalPreferences: {
|
||||||
|
language: 'es',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Reducer(reducer)
|
||||||
|
.withState(initialState)
|
||||||
|
.expect(action)
|
||||||
|
.toReturnState(expectedState);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -46,7 +46,7 @@ function TabComponents({ tabs, customProps = {} }) {
|
|||||||
<div className="dialog-separator-after">
|
<div className="dialog-separator-after">
|
||||||
<ul className="nav nav-tabs">
|
<ul className="nav nav-tabs">
|
||||||
{tabs.map((tab, index) => {
|
{tabs.map((tab, index) => {
|
||||||
const { name, hidden } = tab;
|
const { name, hidden = false } = tab;
|
||||||
return (
|
return (
|
||||||
!hidden && (
|
!hidden && (
|
||||||
<li
|
<li
|
||||||
@ -70,7 +70,11 @@ function TabComponents({ tabs, customProps = {} }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{tabs.map((tab, index) => {
|
{tabs.map((tab, index) => {
|
||||||
const { Component, customProps: tabCustomProps, hidden } = tab;
|
const {
|
||||||
|
Component,
|
||||||
|
customProps: tabCustomProps,
|
||||||
|
hidden = false,
|
||||||
|
} = tab;
|
||||||
return (
|
return (
|
||||||
!hidden && (
|
!hidden && (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -419,7 +419,7 @@ describe('OHIF User Preferences', () => {
|
|||||||
cy.get('.HotkeysPreferences').within(() => {
|
cy.get('.HotkeysPreferences').within(() => {
|
||||||
cy.contains('Rotate Right') // label we're looking for
|
cy.contains('Rotate Right') // label we're looking for
|
||||||
.parent()
|
.parent()
|
||||||
.find('.errorMessage')
|
.find('.preferencesInputErrorMessage')
|
||||||
.as('errorMsg')
|
.as('errorMsg')
|
||||||
.should('have.text', '"Invert" is already using the "i" shortcut.');
|
.should('have.text', '"Invert" is already using the "i" shortcut.');
|
||||||
});
|
});
|
||||||
@ -440,7 +440,7 @@ describe('OHIF User Preferences', () => {
|
|||||||
cy.get('.HotkeysPreferences').within(() => {
|
cy.get('.HotkeysPreferences').within(() => {
|
||||||
cy.contains('Rotate Right') // label we're looking for
|
cy.contains('Rotate Right') // label we're looking for
|
||||||
.parent()
|
.parent()
|
||||||
.find('.errorMessage')
|
.find('.preferencesInputErrorMessage')
|
||||||
.as('errorMsg')
|
.as('errorMsg')
|
||||||
.should('have.text', '"ctrl+z" shortcut combination is not allowed');
|
.should('have.text', '"ctrl+z" shortcut combination is not allowed');
|
||||||
});
|
});
|
||||||
@ -461,7 +461,7 @@ describe('OHIF User Preferences', () => {
|
|||||||
cy.get('.HotkeysPreferences').within(() => {
|
cy.get('.HotkeysPreferences').within(() => {
|
||||||
cy.contains('Zoom Out') // label we're looking for
|
cy.contains('Zoom Out') // label we're looking for
|
||||||
.parent()
|
.parent()
|
||||||
.find('.errorMessage')
|
.find('.preferencesInputErrorMessage')
|
||||||
.as('errorMsg')
|
.as('errorMsg')
|
||||||
.should(
|
.should(
|
||||||
'have.text',
|
'have.text',
|
||||||
|
|||||||
@ -69,6 +69,52 @@ window.config = {
|
|||||||
},
|
},
|
||||||
// ~ Cornerstone Tools
|
// ~ Cornerstone Tools
|
||||||
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
|
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
|
||||||
|
// ~ Window level presets
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset1',
|
||||||
|
label: 'W/L Preset 1',
|
||||||
|
keys: ['1'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset2',
|
||||||
|
label: 'W/L Preset 2',
|
||||||
|
keys: ['2'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset3',
|
||||||
|
label: 'W/L Preset 3',
|
||||||
|
keys: ['3'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset4',
|
||||||
|
label: 'W/L Preset 4',
|
||||||
|
keys: ['4'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset5',
|
||||||
|
label: 'W/L Preset 5',
|
||||||
|
keys: ['5'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset6',
|
||||||
|
label: 'W/L Preset 6',
|
||||||
|
keys: ['6'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset7',
|
||||||
|
label: 'W/L Preset 7',
|
||||||
|
keys: ['7'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset8',
|
||||||
|
label: 'W/L Preset 8',
|
||||||
|
keys: ['8'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset9',
|
||||||
|
label: 'W/L Preset 9',
|
||||||
|
keys: ['9'],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
cornerstoneExtensionConfig: {},
|
cornerstoneExtensionConfig: {},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -58,6 +58,52 @@ window.config = {
|
|||||||
keys: ['pageup'],
|
keys: ['pageup'],
|
||||||
},
|
},
|
||||||
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
|
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
|
||||||
|
// ~ Window level presets
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset1',
|
||||||
|
label: 'W/L Preset 1',
|
||||||
|
keys: ['1'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset2',
|
||||||
|
label: 'W/L Preset 2',
|
||||||
|
keys: ['2'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset3',
|
||||||
|
label: 'W/L Preset 3',
|
||||||
|
keys: ['3'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset4',
|
||||||
|
label: 'W/L Preset 4',
|
||||||
|
keys: ['4'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset5',
|
||||||
|
label: 'W/L Preset 5',
|
||||||
|
keys: ['5'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset6',
|
||||||
|
label: 'W/L Preset 6',
|
||||||
|
keys: ['6'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset7',
|
||||||
|
label: 'W/L Preset 7',
|
||||||
|
keys: ['7'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset8',
|
||||||
|
label: 'W/L Preset 8',
|
||||||
|
keys: ['8'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset9',
|
||||||
|
label: 'W/L Preset 9',
|
||||||
|
keys: ['9'],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
i18n: {
|
i18n: {
|
||||||
LOCIZE_PROJECTID: 'a8da3f9a-e467-4dd6-af33-474d582a0294',
|
LOCIZE_PROJECTID: 'a8da3f9a-e467-4dd6-af33-474d582a0294',
|
||||||
|
|||||||
@ -64,6 +64,52 @@ window.config = {
|
|||||||
},
|
},
|
||||||
// ~ Cornerstone Tools
|
// ~ Cornerstone Tools
|
||||||
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
|
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
|
||||||
|
// ~ Window level presets
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset1',
|
||||||
|
label: 'W/L Preset 1',
|
||||||
|
keys: ['1'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset2',
|
||||||
|
label: 'W/L Preset 2',
|
||||||
|
keys: ['2'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset3',
|
||||||
|
label: 'W/L Preset 3',
|
||||||
|
keys: ['3'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset4',
|
||||||
|
label: 'W/L Preset 4',
|
||||||
|
keys: ['4'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset5',
|
||||||
|
label: 'W/L Preset 5',
|
||||||
|
keys: ['5'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset6',
|
||||||
|
label: 'W/L Preset 6',
|
||||||
|
keys: ['6'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset7',
|
||||||
|
label: 'W/L Preset 7',
|
||||||
|
keys: ['7'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset8',
|
||||||
|
label: 'W/L Preset 8',
|
||||||
|
keys: ['8'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: 'windowLevelPreset9',
|
||||||
|
label: 'W/L Preset 9',
|
||||||
|
keys: ['9'],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
i18n: {
|
i18n: {
|
||||||
LOCIZE_PROJECTID: 'a8da3f9a-e467-4dd6-af33-474d582a0294',
|
LOCIZE_PROJECTID: 'a8da3f9a-e467-4dd6-af33-474d582a0294',
|
||||||
|
|||||||
@ -1,74 +1,140 @@
|
|||||||
import { redux, utils } from '@ohif/core';
|
import { redux } from '@ohif/core';
|
||||||
import store from './../../store';
|
import store from './../../store';
|
||||||
const { setViewportActive, setActiveViewportSpecificData } = redux.actions;
|
|
||||||
|
|
||||||
const actions = {
|
const commandsModule = ({ commandsManager }) => {
|
||||||
updateActiveViewport: ({ viewports, direction }) => {
|
const { setViewportActive, setActiveViewportSpecificData } = redux.actions;
|
||||||
const { viewportSpecificData, activeViewportIndex } = viewports;
|
|
||||||
const maxIndex = Object.keys(viewportSpecificData).length - 1;
|
|
||||||
|
|
||||||
let newIndex = activeViewportIndex + direction;
|
const actions = {
|
||||||
newIndex = newIndex > maxIndex ? 0 : newIndex;
|
updateActiveViewport: ({ viewports, direction }) => {
|
||||||
newIndex = newIndex < 0 ? maxIndex : newIndex;
|
const { viewportSpecificData, activeViewportIndex } = viewports;
|
||||||
|
const maxIndex = Object.keys(viewportSpecificData).length - 1;
|
||||||
|
|
||||||
store.dispatch(setViewportActive(newIndex));
|
let newIndex = activeViewportIndex + direction;
|
||||||
},
|
newIndex = newIndex > maxIndex ? 0 : newIndex;
|
||||||
updateViewportDisplaySet: ({ viewports, direction }) => {
|
newIndex = newIndex < 0 ? maxIndex : newIndex;
|
||||||
const viewportSpecificData = { ...viewports.viewportSpecificData };
|
|
||||||
const activeViewport = viewportSpecificData[viewports.activeViewportIndex];
|
|
||||||
const studyMetadata = utils.studyMetadataManager.get(
|
|
||||||
activeViewport.studyInstanceUid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!studyMetadata) {
|
store.dispatch(setViewportActive(newIndex));
|
||||||
return;
|
},
|
||||||
}
|
setWindowLevelPreset: ({ viewports, preset }) => {
|
||||||
|
const state = store.getState();
|
||||||
|
const { preferences = {} } = state;
|
||||||
|
const { window, level } =
|
||||||
|
preferences.windowLevelData && preferences.windowLevelData[preset];
|
||||||
|
|
||||||
const allDisplaySets = studyMetadata.getDisplaySets();
|
if (window && level) {
|
||||||
const currentDisplaySetIndex = allDisplaySets.findIndex(
|
commandsManager.runCommand('setWindowLevel', {
|
||||||
displaySet =>
|
viewports,
|
||||||
displaySet.displaySetInstanceUid ===
|
window,
|
||||||
activeViewport.displaySetInstanceUid
|
level,
|
||||||
);
|
});
|
||||||
if (currentDisplaySetIndex < 0) {
|
}
|
||||||
return;
|
},
|
||||||
}
|
updateViewportDisplaySet: ({ viewports, direction }) => {
|
||||||
|
const viewportSpecificData = { ...viewports.viewportSpecificData };
|
||||||
|
const activeViewport =
|
||||||
|
viewportSpecificData[viewports.activeViewportIndex];
|
||||||
|
const studyMetadata = utils.studyMetadataManager.get(
|
||||||
|
activeViewport.studyInstanceUid
|
||||||
|
);
|
||||||
|
|
||||||
const newDisplaySetIndex = currentDisplaySetIndex + direction;
|
if (!studyMetadata) {
|
||||||
const newDisplaySetData = allDisplaySets[newDisplaySetIndex];
|
return;
|
||||||
if (!newDisplaySetData) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
store.dispatch(setActiveViewportSpecificData(newDisplaySetData));
|
const allDisplaySets = studyMetadata.getDisplaySets();
|
||||||
},
|
const currentDisplaySetIndex = allDisplaySets.findIndex(
|
||||||
|
displaySet =>
|
||||||
|
displaySet.displaySetInstanceUid ===
|
||||||
|
activeViewport.displaySetInstanceUid
|
||||||
|
);
|
||||||
|
if (currentDisplaySetIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newDisplaySetIndex = currentDisplaySetIndex + direction;
|
||||||
|
const newDisplaySetData = allDisplaySets[newDisplaySetIndex];
|
||||||
|
if (!newDisplaySetData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
store.dispatch(setActiveViewportSpecificData(newDisplaySetData));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const definitions = {
|
||||||
|
// Next/Previous active viewport
|
||||||
|
incrementActiveViewport: {
|
||||||
|
commandFn: actions.updateActiveViewport,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { direction: 1 },
|
||||||
|
},
|
||||||
|
decrementActiveViewport: {
|
||||||
|
commandFn: actions.updateActiveViewport,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { direction: -1 },
|
||||||
|
},
|
||||||
|
// Window level Presets
|
||||||
|
windowLevelPreset1: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 1 },
|
||||||
|
},
|
||||||
|
windowLevelPreset2: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 2 },
|
||||||
|
},
|
||||||
|
windowLevelPreset3: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 3 },
|
||||||
|
},
|
||||||
|
windowLevelPreset4: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 4 },
|
||||||
|
},
|
||||||
|
windowLevelPreset5: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 5 },
|
||||||
|
},
|
||||||
|
windowLevelPreset6: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 6 },
|
||||||
|
},
|
||||||
|
windowLevelPreset7: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 7 },
|
||||||
|
},
|
||||||
|
windowLevelPreset8: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 8 },
|
||||||
|
},
|
||||||
|
windowLevelPreset9: {
|
||||||
|
commandFn: actions.setWindowLevelPreset,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { preset: 9 },
|
||||||
|
},
|
||||||
|
nextViewportDisplaySet: {
|
||||||
|
commandFn: actions.updateViewportDisplaySet,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { direction: 1 },
|
||||||
|
},
|
||||||
|
previousViewportDisplaySet: {
|
||||||
|
commandFn: actions.updateViewportDisplaySet,
|
||||||
|
storeContexts: ['viewports'],
|
||||||
|
options: { direction: -1 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
definitions,
|
||||||
|
defaultContext: 'VIEWER',
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const definitions = {
|
export default commandsModule;
|
||||||
// Next/Previous active viewport
|
|
||||||
incrementActiveViewport: {
|
|
||||||
commandFn: actions.updateActiveViewport,
|
|
||||||
storeContexts: ['viewports'],
|
|
||||||
options: { direction: 1 },
|
|
||||||
},
|
|
||||||
decrementActiveViewport: {
|
|
||||||
commandFn: actions.updateActiveViewport,
|
|
||||||
storeContexts: ['viewports'],
|
|
||||||
options: { direction: -1 },
|
|
||||||
},
|
|
||||||
nextViewportDisplaySet: {
|
|
||||||
commandFn: actions.updateViewportDisplaySet,
|
|
||||||
storeContexts: ['viewports'],
|
|
||||||
options: { direction: 1 },
|
|
||||||
},
|
|
||||||
previousViewportDisplaySet: {
|
|
||||||
commandFn: actions.updateViewportDisplaySet,
|
|
||||||
storeContexts: ['viewports'],
|
|
||||||
options: { direction: -1 },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
definitions,
|
|
||||||
defaultContext: 'VIEWER',
|
|
||||||
};
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import commandsModule from './commandsModule.js';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
id: 'generic-viewer-commands',
|
id: 'generic-viewer-commands',
|
||||||
getCommandsModule() {
|
getCommandsModule({ commandsManager }) {
|
||||||
return commandsModule;
|
return commandsModule({ commandsManager });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -168,9 +168,11 @@ function HotkeysPreferences({ onClose }) {
|
|||||||
keys={keys}
|
keys={keys}
|
||||||
modifier_keys={MODIFIER_KEYS}
|
modifier_keys={MODIFIER_KEYS}
|
||||||
handleChange={handleChange}
|
handleChange={handleChange}
|
||||||
classNames={'hotkeyInput'}
|
classNames={'preferencesInput'}
|
||||||
></HotkeyField>
|
></HotkeyField>
|
||||||
<span className="errorMessage">{errorMessage}</span>
|
<span className="preferencesInputErrorMessage">
|
||||||
|
{errorMessage}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,11 +2,6 @@
|
|||||||
display: flex
|
display: flex
|
||||||
padding: 20px
|
padding: 20px
|
||||||
|
|
||||||
.errorMessage
|
|
||||||
color: var(--state-error-text)
|
|
||||||
font-size: 10px
|
|
||||||
text-transform: uppercase
|
|
||||||
|
|
||||||
.hotkeyTable
|
.hotkeyTable
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: row
|
flex-direction: row
|
||||||
@ -40,28 +35,6 @@
|
|||||||
flex-basis: 0
|
flex-basis: 0
|
||||||
flex-grow: 1.5
|
flex-grow: 1.5
|
||||||
|
|
||||||
.hotkeyInput
|
|
||||||
font-weight: 400
|
|
||||||
cursor: pointer
|
|
||||||
transition: background-color .3s ease,border-color .3s ease
|
|
||||||
background-color: var(--ui-gray)
|
|
||||||
color: var(--text-primary-color)
|
|
||||||
border-color: var(--ui-border-coolor)
|
|
||||||
border: 0
|
|
||||||
border-radius: 2px
|
|
||||||
font-size: 14px
|
|
||||||
height: 30px
|
|
||||||
width: 100%
|
|
||||||
line-height: 16px
|
|
||||||
padding: 8px 9px 6px
|
|
||||||
text-align: center
|
|
||||||
|
|
||||||
.hotkeyInput:focus
|
|
||||||
border-color: var(--active-color)
|
|
||||||
background-color: var(--ui-gray-dark)
|
|
||||||
box-shadow: 0 0 0 2px var(--active-color) !important
|
|
||||||
outline: 0
|
|
||||||
|
|
||||||
.hotkeyLabel
|
.hotkeyLabel
|
||||||
padding: 5px 15px 5px 0
|
padding: 5px 15px 5px 0
|
||||||
text-align: right
|
text-align: right
|
||||||
@ -69,5 +42,5 @@
|
|||||||
flex-grow: 1.5
|
flex-grow: 1.5
|
||||||
|
|
||||||
.stateError
|
.stateError
|
||||||
.hotkeyInput
|
.preferencesInput
|
||||||
background-color: var(--state-error)
|
background-color: var(--state-error)
|
||||||
|
|||||||
@ -8,24 +8,23 @@ import { HotkeysPreferences } from './HotkeysPreferences';
|
|||||||
import { WindowLevelPreferences } from './WindowLevelPreferences';
|
import { WindowLevelPreferences } from './WindowLevelPreferences';
|
||||||
import { GeneralPreferences } from './GeneralPreferences';
|
import { GeneralPreferences } from './GeneralPreferences';
|
||||||
|
|
||||||
|
import './UserPreferences.styl';
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
name: 'Hotkeys',
|
name: 'Hotkeys',
|
||||||
Component: HotkeysPreferences,
|
Component: HotkeysPreferences,
|
||||||
customProps: {},
|
customProps: {},
|
||||||
hidden: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'General',
|
name: 'General',
|
||||||
Component: GeneralPreferences,
|
Component: GeneralPreferences,
|
||||||
customProps: {},
|
customProps: {},
|
||||||
hidden: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Window Level',
|
name: 'Window Level',
|
||||||
Component: WindowLevelPreferences,
|
Component: WindowLevelPreferences,
|
||||||
customProps: {},
|
customProps: {},
|
||||||
hidden: true,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
.preferencesInputErrorMessage
|
||||||
|
color: var(--state-error-text)
|
||||||
|
font-size: 10px
|
||||||
|
text-transform: uppercase
|
||||||
|
|
||||||
|
.preferencesInput
|
||||||
|
font-weight: 400
|
||||||
|
cursor: pointer
|
||||||
|
transition: background-color .3s ease,border-color .3s ease
|
||||||
|
background-color: var(--ui-gray)
|
||||||
|
color: var(--text-primary-color)
|
||||||
|
border-color: var(--ui-border-coolor)
|
||||||
|
border: 0
|
||||||
|
border-radius: 2px
|
||||||
|
font-size: 14px
|
||||||
|
height: 30px
|
||||||
|
width: 100%
|
||||||
|
line-height: 16px
|
||||||
|
padding: 8px 9px 6px
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.preferencesInput:focus
|
||||||
|
border-color: var(--active-color)
|
||||||
|
background-color: var(--ui-gray-dark)
|
||||||
|
box-shadow: 0 0 0 2px var(--active-color) !important
|
||||||
|
outline: 0
|
||||||
@ -1,19 +1,115 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
import { redux } from '@ohif/core';
|
||||||
|
|
||||||
import { TabFooter } from '@ohif/ui';
|
import { TabFooter, useSnackbarContext } from '@ohif/ui';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const { actions } = redux;
|
||||||
|
|
||||||
|
import './WindowLevelPreferences.styl';
|
||||||
|
|
||||||
function WindowLevelPreferences({ onClose }) {
|
function WindowLevelPreferences({ onClose }) {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const windowLevelData = useSelector(state => {
|
||||||
|
const { preferences = {} } = state;
|
||||||
|
const { windowLevelData } = preferences;
|
||||||
|
|
||||||
|
return windowLevelData;
|
||||||
|
});
|
||||||
|
|
||||||
|
const [state, setState] = useState({
|
||||||
|
values: { ...windowLevelData },
|
||||||
|
});
|
||||||
|
|
||||||
const { t } = useTranslation('UserPreferencesModal');
|
const { t } = useTranslation('UserPreferencesModal');
|
||||||
const onResetPreferences = () => {};
|
const onResetPreferences = () => {};
|
||||||
const onSave = () => {};
|
|
||||||
const hasErrors = false;
|
const hasErrors = false;
|
||||||
|
const onSave = () => {
|
||||||
|
dispatch(actions.setUserPreferences({ windowLevelData: state.values }));
|
||||||
|
|
||||||
|
onClose();
|
||||||
|
|
||||||
|
snackbar.show({
|
||||||
|
message: t('SaveMessage'),
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const snackbar = useSnackbarContext();
|
||||||
|
|
||||||
|
const handleInputChange = event => {
|
||||||
|
const $target = event.target;
|
||||||
|
const { key, inputname } = $target.dataset;
|
||||||
|
const inputValue = $target.value;
|
||||||
|
|
||||||
|
if (!state.values[key] || !state.values[key][inputname]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(prevState => ({
|
||||||
|
...prevState,
|
||||||
|
values: {
|
||||||
|
...prevState.values,
|
||||||
|
[key]: {
|
||||||
|
...prevState.values[key],
|
||||||
|
[inputname]: inputValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="">Component content: {name}</div>
|
<div className="WindowLevelPreferences">
|
||||||
<div className="">TDB!</div>
|
<div className="wlColumn">
|
||||||
|
<div className="wlRow header">
|
||||||
|
<div className="wlColumn preset">Preset</div>
|
||||||
|
<div className="wlColumn description">Description</div>
|
||||||
|
<div className="wlColumn window">Window</div>
|
||||||
|
<div className="wlColumn level">Level</div>
|
||||||
|
</div>
|
||||||
|
{Object.keys(state.values).map((key, index) => {
|
||||||
|
return (
|
||||||
|
<div className="wlRow" key={key}>
|
||||||
|
<div className="wlColumn preset">{key}</div>
|
||||||
|
<div className="wlColumn description">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="preferencesInput"
|
||||||
|
value={state.values[key].description}
|
||||||
|
data-key={key}
|
||||||
|
data-inputname="description"
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="wlColumn window">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="preferencesInput"
|
||||||
|
value={state.values[key].window}
|
||||||
|
data-key={key}
|
||||||
|
data-inputname="window"
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="wlColumn level">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="preferencesInput"
|
||||||
|
value={state.values[key].level}
|
||||||
|
data-key={key}
|
||||||
|
data-inputname="level"
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<TabFooter
|
<TabFooter
|
||||||
onResetPreferences={onResetPreferences}
|
onResetPreferences={onResetPreferences}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
.WindowLevelPreferences
|
||||||
|
display: flex
|
||||||
|
padding: 20px 0
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.wlColumn
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
flex-basis: 0
|
||||||
|
flex-grow: 1.5
|
||||||
|
margin: 0 5px
|
||||||
|
|
||||||
|
.wlRow
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
margin: 5px 0
|
||||||
|
|
||||||
|
.header
|
||||||
|
|
||||||
|
.preset
|
||||||
|
flex-grow: 0.5
|
||||||
|
|
||||||
|
.window,
|
||||||
|
.level
|
||||||
|
flex-grow: 1
|
||||||
|
|
||||||
|
.description
|
||||||
|
flex-grow: 2
|
||||||
Loading…
Reference in New Issue
Block a user