From ff28a2264b52def0aace23971036c4563e18617d Mon Sep 17 00:00:00 2001 From: Erik Ziegler Date: Wed, 21 Jul 2021 12:58:15 +0200 Subject: [PATCH] fixes for hotkeys usage in docusaurus --- README.md | 2 +- extensions/default/src/ViewerLayout/index.jsx | 4 +- modes/longitudinal/src/index.js | 3 +- platform/core/package.json | 3 +- platform/core/src/classes/HotkeysManager.js | 2 +- platform/core/src/utils/index.js | 4 +- .../docs/deployment/build-for-production.md | 2 +- platform/docs/docs/development/our-process.md | 2 +- .../extensions/modules/data-source.md | 42 +-- platform/docs/docs/platform/modes/routes.md | 2 +- .../src/components/AboutModal/AboutModal.jsx | 2 +- .../components/HotkeyField/HotkeyField.jsx | 10 +- .../HotkeysPreferences/HotkeysPreferences.jsx | 10 +- .../components/HotkeysPreferences/utils.js | 5 +- .../UserPreferences/UserPreferences.jsx | 10 +- platform/ui/src/index.js | 7 +- platform/ui/src/utils/getMockedStudies.js | 17 - platform/ui/src/utils/hotkeys/index.js | 14 - platform/ui/src/utils/hotkeys/pausePlugin.js | 32 -- platform/ui/src/utils/hotkeys/recordPlugin.js | 218 ------------- platform/ui/src/utils/index.js | 8 - platform/ui/src/views/StudyList/StudyList.js | 295 ------------------ .../viewer/src/routes/WorkList/WorkList.jsx | 5 +- yarn.lock | 21 +- 24 files changed, 61 insertions(+), 659 deletions(-) delete mode 100644 platform/ui/src/utils/getMockedStudies.js delete mode 100644 platform/ui/src/utils/hotkeys/index.js delete mode 100644 platform/ui/src/utils/hotkeys/pausePlugin.js delete mode 100644 platform/ui/src/utils/hotkeys/recordPlugin.js delete mode 100644 platform/ui/src/utils/index.js delete mode 100644 platform/ui/src/views/StudyList/StudyList.js diff --git a/README.md b/README.md index d04be0ccb..a9ef39699 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

OHIF Medical Imaging Viewer

-

The OHIF Viewer is a zero-footprint medical image viewer provided by the Open Health Imaging Foundation (OHIF). It is a configurable and extensible progressive web application with out-of-the-box support for image archives which support DICOMweb.

+

The OHIF Viewer is a zero-footprint medical image viewer provided by the Open Health Imaging Foundation (OHIF). It is a configurable and extensible progressive web application with out-of-the-box support for image archives which support DICOMweb.

diff --git a/extensions/default/src/ViewerLayout/index.jsx b/extensions/default/src/ViewerLayout/index.jsx index 74bb7e398..faf208b13 100644 --- a/extensions/default/src/ViewerLayout/index.jsx +++ b/extensions/default/src/ViewerLayout/index.jsx @@ -11,11 +11,9 @@ import { } from '@ohif/ui'; import i18n from '@ohif/i18n'; -import { utils } from '@ohif/ui'; +import { hotkeys } from '@ohif/core'; import { useNavigate } from 'react-router-dom'; -const { hotkeys } = utils; - const { availableLanguages, defaultLanguage, currentLanguage } = i18n; import { useAppConfig } from '@state'; diff --git a/modes/longitudinal/src/index.js b/modes/longitudinal/src/index.js index 69f83a280..56f0e58bd 100644 --- a/modes/longitudinal/src/index.js +++ b/modes/longitudinal/src/index.js @@ -1,6 +1,5 @@ import toolbarButtons from './toolbarButtons.js'; -import { utils } from '@ohif/ui'; -const { hotkeys } = utils; +import { hotkeys } from '@ohif/core'; const ohif = { layout: 'org.ohif.default.layoutTemplateModule.viewerLayout', diff --git a/platform/core/package.json b/platform/core/package.json index 7c69f5c6e..93f380b14 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -34,7 +34,8 @@ "cornerstone-tools": "5.1.2", "cornerstone-math": "0.1.9", "cornerstone-wado-image-loader": "^3.1.2", - "dicom-parser": "^1.8.3" + "dicom-parser": "^1.8.3", + "@ohif/ui": "^1.8.2" }, "dependencies": { "@babel/runtime": "7.7.6", diff --git a/platform/core/src/classes/HotkeysManager.js b/platform/core/src/classes/HotkeysManager.js index b8b2a5a9c..afd4ffea2 100644 --- a/platform/core/src/classes/HotkeysManager.js +++ b/platform/core/src/classes/HotkeysManager.js @@ -1,6 +1,6 @@ import objectHash from 'object-hash'; import log from './../log.js'; -import hotkeys from './../utils/hotkeys'; +import { hotkeys } from '../utils'; /** * diff --git a/platform/core/src/utils/index.js b/platform/core/src/utils/index.js index 81355fb71..baed6ace7 100644 --- a/platform/core/src/utils/index.js +++ b/platform/core/src/utils/index.js @@ -46,7 +46,7 @@ const utils = { resolveObjectPath, hierarchicalListUtils, progressTrackingUtils, - isLowPriorityModality + isLowPriorityModality, }; export { @@ -69,7 +69,7 @@ export { resolveObjectPath, hierarchicalListUtils, progressTrackingUtils, - isLowPriorityModality + isLowPriorityModality, }; export default utils; diff --git a/platform/docs/docs/deployment/build-for-production.md b/platform/docs/docs/deployment/build-for-production.md index 2ef2014e0..cc3d55c5d 100644 --- a/platform/docs/docs/deployment/build-for-production.md +++ b/platform/docs/docs/deployment/build-for-production.md @@ -70,7 +70,7 @@ and registered extension's features, are configured using this file. The easiest way to apply your own configuration is to modify the `default.js` file. For more advanced cofiguration options, check out our -[configuration essentials guide](../configuring/index.md). +[configuration essentials guide](../../configuration/index.md). ## Next Steps diff --git a/platform/docs/docs/development/our-process.md b/platform/docs/docs/development/our-process.md index a47d4e48a..8a3f51b7b 100644 --- a/platform/docs/docs/development/our-process.md +++ b/platform/docs/docs/development/our-process.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 4 sidebar_label: Issue & PR Triage Process --- diff --git a/platform/docs/docs/platform/extensions/modules/data-source.md b/platform/docs/docs/platform/extensions/modules/data-source.md index e98f7d8ea..01439d9cd 100644 --- a/platform/docs/docs/platform/extensions/modules/data-source.md +++ b/platform/docs/docs/platform/extensions/modules/data-source.md @@ -2,27 +2,17 @@ sidebar_position: 3 sidebar_label: Data Source --- - # Module: Data Source + ## Overview +The internal data structure of OHIF’s metadata follows naturalized DICOM JSON, A format pioneered by `dcmjs`. In short DICOM metadata headers with DICOM Keywords instead of tags and sequences as arrays, for easy development and clear code. -The internal data structure of OHIF’s metadata follows naturalized DICOM JSON, A -format pioneered by `dcmjs`. In short DICOM metadata headers with DICOM Keywords -instead of tags and sequences as arrays, for easy development and clear code. +We have built a standard for fetching and mapping data into OHIF’s native format, which we call DataSources, and have provided one implementation of this standard. -We have built a standard for fetching and mapping data into OHIF’s native -format, which we call DataSources, and have provided one implementation of this -standard. +You can make another datasource implementation which communicates to your backend and maps to OHIF’s native format, then use any existing mode on your platform. Your data doesn’t even need to be DICOM if you can map some proprietary data to the correct format. -You can make another datasource implementation which communicates to your -backend and maps to OHIF’s native format, then use any existing mode on your -platform. Your data doesn’t even need to be DICOM if you can map some -proprietary data to the correct format. - -The DataSource is also a place to add easy helper methods that platform-specific -extensions can call in order to interact with the backend, meaning proprietary -data interactions can be wrapped in extensions. +The DataSource is also a place to add easy helper methods that platform-specific extensions can call in order to interact with the backend, meaning proprietary data interactions can be wrapped in extensions. ```js const getDataSourcesModule = () => [ @@ -36,13 +26,13 @@ const getDataSourcesModule = () => [ ]; ``` -Default extension provides two main data sources that are commonly used: -`dicomweb` and `dicomjson` +Default extension provides two main data sources that are commonly used: `dicomweb` and `dicomjson` ```js import { createDicomWebApi } from './DicomWebDataSource/index.js'; import { createDicomJSONApi } from './DicomJSONDataSource/index.js'; + function getDataSourcesModule() { return [ { @@ -59,14 +49,13 @@ function getDataSourcesModule() { } ``` + ## Custom DataSource +You can add your custom datasource by creating the implementation using `IWebApiDataSource.create` from `@ohif/core`. This factory function creates a new "Web API" data source that fetches data over HTTP. + +You need to make sure, you implement the following functions for the data source. -You can add your custom datasource by creating the implementation using -`IWebApiDataSource.create` from `@ohif/core`. This factory function creates a -new "Web API" data source that fetches data over HTTP. -You need to make sure, you implement the following functions for the data -source. ```js title="platform/core/src/DataSources/IWebApiDataSource.js" function create({ @@ -87,9 +76,8 @@ function create({ You can take a look at `dicomweb` data source implementation to get an idea `extensions/default/src/DicomWebDataSource/index.js` -## DicomMetadataStore -In `OHIF-v3` we have a central location for the metadata of studies and they are -located in `DicomMetadataStore`. Your custom datasource can communicate with -`DicomMetadataStore` to store, and fetch Study/Series/Instance metadata. We will -learn more about `DicomMetadataStore` in services. + +## DicomMetadataStore +In `OHIF-v3` we have a central location for the metadata of studies and they are located +in `DicomMetadataStore`. Your custom datasource can communicate with `DicomMetadataStore` to store, and fetch Study/Series/Instance metadata. We will learn more about `DicomMetadataStore` in services. diff --git a/platform/docs/docs/platform/modes/routes.md b/platform/docs/docs/platform/modes/routes.md index 3e616b2c8..2d1e691b9 100644 --- a/platform/docs/docs/platform/modes/routes.md +++ b/platform/docs/docs/platform/modes/routes.md @@ -78,7 +78,7 @@ There are two types of `routes` that are created by the mode. - Routes with dataSourceName `/${mode.id}/${dataSourceName}` - Routes without dataSourceName `/${mode.id}` -Therefore navigating to `http://localhost:3000/viewer/?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1` will run the app with the layout and functionalities of the `viewer` mode using the `defaultDataSourceName` which is defined in the [App Config](../configuring/index.md) +Therefore navigating to `http://localhost:3000/viewer/?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1` will run the app with the layout and functionalities of the `viewer` mode using the `defaultDataSourceName` which is defined in the [App Config](../../configuration/index.md) You can use the same exact mode using a different registered data source (e.g., `dicomjson`) by navigating to `http://localhost:3000/viewer/dicomjson/?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1` diff --git a/platform/ui/src/components/AboutModal/AboutModal.jsx b/platform/ui/src/components/AboutModal/AboutModal.jsx index 28b663622..e1754fdcf 100644 --- a/platform/ui/src/components/AboutModal/AboutModal.jsx +++ b/platform/ui/src/components/AboutModal/AboutModal.jsx @@ -72,7 +72,7 @@ const AboutModal = ({buildNumber, versionNumber}) => { - + More details diff --git a/platform/ui/src/components/HotkeyField/HotkeyField.jsx b/platform/ui/src/components/HotkeyField/HotkeyField.jsx index 3c5d13e9d..3173ddc3c 100644 --- a/platform/ui/src/components/HotkeyField/HotkeyField.jsx +++ b/platform/ui/src/components/HotkeyField/HotkeyField.jsx @@ -2,7 +2,6 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import Input from '../Input'; -import { hotkeys } from '../../utils/' import { getKeys, formatKeysForInput } from './utils'; /** @@ -16,7 +15,7 @@ import { getKeys, formatKeysForInput } from './utils'; * @param {string} props.className input classes * @param {Array[]} props.modifierKeys */ -const HotkeyField = ({ disabled, keys, onChange, className, modifierKeys }) => { +const HotkeyField = ({ disabled, keys, onChange, className, modifierKeys, hotkeys }) => { const inputValue = formatKeysForInput(keys); useEffect(() => { @@ -57,6 +56,13 @@ HotkeyField.propTypes = { className: PropTypes.string, modifierKeys: PropTypes.array, disabled: PropTypes.bool, + hotkeys: PropTypes.object({ + initialize: PropTypes.func.isRequired, + pause: PropTypes.func.isRequired, + unpause: PropTypes.func.isRequired, + startRecording: PropTypes.func.isRequired, + record: PropTypes.func.isRequired, + }).isRequired }; HotkeyField.defaultProps = { diff --git a/platform/ui/src/components/HotkeysPreferences/HotkeysPreferences.jsx b/platform/ui/src/components/HotkeysPreferences/HotkeysPreferences.jsx index 71c7cadef..480cb29a2 100644 --- a/platform/ui/src/components/HotkeysPreferences/HotkeysPreferences.jsx +++ b/platform/ui/src/components/HotkeysPreferences/HotkeysPreferences.jsx @@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next'; import { MODIFIER_KEYS } from './hotkeysConfig'; import { validate, splitHotkeyDefinitionsAndCreateTuples } from './utils'; -const HotkeysPreferences = ({ disabled, hotkeyDefinitions, errors: controlledErrors, onChange }) => { +const HotkeysPreferences = ({ disabled, hotkeyDefinitions, errors: controlledErrors, onChange, hotkeysModule }) => { const { t } = useTranslation('UserPreferencesModal'); const visibleHotkeys = Object.keys(hotkeyDefinitions) @@ -83,6 +83,7 @@ const HotkeysPreferences = ({ disabled, hotkeyDefinitions, errors: controlledErr keys={definition.keys} modifierKeys={MODIFIER_KEYS} onChange={onChangeHandler} + hotkeys={hotkeysModule} className='text-lg h-8' /> {error && {error}} @@ -106,6 +107,13 @@ HotkeysPreferences.propTypes = { onChange: PropTypes.func, disabled: PropTypes.bool, hotkeyDefinitions: PropTypes.object.isRequired, + hotkeysModule: PropTypes.object({ + initialize: PropTypes.func.isRequired, + pause: PropTypes.func.isRequired, + unpause: PropTypes.func.isRequired, + startRecording: PropTypes.func.isRequired, + record: PropTypes.func.isRequired, + }).isRequired }; HotkeysPreferences.defaultProps = { diff --git a/platform/ui/src/components/HotkeysPreferences/utils.js b/platform/ui/src/components/HotkeysPreferences/utils.js index 3b0fa0aef..221dc5a3d 100644 --- a/platform/ui/src/components/HotkeysPreferences/utils.js +++ b/platform/ui/src/components/HotkeysPreferences/utils.js @@ -46,7 +46,4 @@ const validate = ({ commandName, pressedKeys, hotkeys }) => { return { error: undefined }; }; -export { - validate, - splitHotkeyDefinitionsAndCreateTuples -}; +export { validate, splitHotkeyDefinitionsAndCreateTuples }; diff --git a/platform/ui/src/components/UserPreferences/UserPreferences.jsx b/platform/ui/src/components/UserPreferences/UserPreferences.jsx index 97e38a5b8..00634ec75 100644 --- a/platform/ui/src/components/UserPreferences/UserPreferences.jsx +++ b/platform/ui/src/components/UserPreferences/UserPreferences.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Select, Typography, Button, HotkeysPreferences } from '../'; import { useTranslation } from 'react-i18next'; -const UserPreferences = ({ availableLanguages, defaultLanguage, currentLanguage, disabled, hotkeyDefinitions, hotkeyDefaults, onCancel, onSubmit, onReset }) => { +const UserPreferences = ({ availableLanguages, defaultLanguage, currentLanguage, disabled, hotkeyDefinitions, hotkeyDefaults, onCancel, onSubmit, onReset, hotkeysModule }) => { const { t } = useTranslation('UserPreferencesModal'); const [state, setState] = useState({ isDisabled: disabled, @@ -85,6 +85,7 @@ const UserPreferences = ({ availableLanguages, defaultLanguage, currentLanguage, hotkeyDefinitions={state.hotkeyDefinitions} onChange={onHotkeysChangeHandler} errors={state.hotkeyErrors} + hotkeysModule={hotkeysModule} />
@@ -125,6 +126,13 @@ UserPreferences.propTypes = { onCancel: PropTypes.func, onSubmit: PropTypes.func, onReset: PropTypes.func, + hotkeysModule: PropTypes.object({ + initialize: PropTypes.func.isRequired, + pause: PropTypes.func.isRequired, + unpause: PropTypes.func.isRequired, + startRecording: PropTypes.func.isRequired, + record: PropTypes.func.isRequired, + }).isRequired }; UserPreferences.defaultProps = { diff --git a/platform/ui/src/index.js b/platform/ui/src/index.js index a5995f413..d80db595d 100644 --- a/platform/ui/src/index.js +++ b/platform/ui/src/index.js @@ -1,6 +1,6 @@ /** UTILS */ -import utils from './utils'; -export { utils }; +//import utils from './utils'; +//export { utils }; /** CONTEXT/HOOKS */ export { @@ -102,6 +102,3 @@ export { export { getIcon, ICONS } from './components/Icon/getIcon'; export { BackgroundColor } from './pages/Colors/BackgroundColor'; export { ModalComponent } from './contextProviders/ModalComponent'; - -/** VIEWS */ -export { StudyList, Viewer } from './views'; diff --git a/platform/ui/src/utils/getMockedStudies.js b/platform/ui/src/utils/getMockedStudies.js deleted file mode 100644 index 678d79bf8..000000000 --- a/platform/ui/src/utils/getMockedStudies.js +++ /dev/null @@ -1,17 +0,0 @@ -import studyListMock from '../mocks/studyList.json'; - -/** Values can be env vars */ -const DEFAULT_MOCKED_STUDIES_LIMIT = 1000; - -/** - * Method to get a mocked study list - * @param {number} items Number of studies to be loaded - * @returns {array} Study list - */ -const getMockedStudies = (items = 50) => { - const num = - items > DEFAULT_MOCKED_STUDIES_LIMIT ? DEFAULT_MOCKED_STUDIES_LIMIT : items; - return new Array(num).fill(studyListMock.studies[0]); -}; - -export default getMockedStudies; diff --git a/platform/ui/src/utils/hotkeys/index.js b/platform/ui/src/utils/hotkeys/index.js deleted file mode 100644 index 9118e672f..000000000 --- a/platform/ui/src/utils/hotkeys/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import Mousetrap from 'mousetrap'; -import pausePlugin from './pausePlugin'; -import recordPlugin from './recordPlugin'; - -Mousetrap.initialize = () => { - if (!Mousetrap._initialized) { - recordPlugin(Mousetrap); - pausePlugin(Mousetrap); - - Mousetrap._initialized = true; - } -}; - -export default Mousetrap; diff --git a/platform/ui/src/utils/hotkeys/pausePlugin.js b/platform/ui/src/utils/hotkeys/pausePlugin.js deleted file mode 100644 index 80c5513f0..000000000 --- a/platform/ui/src/utils/hotkeys/pausePlugin.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * adds a pause and unpause method to Mousetrap - * this allows you to enable or disable keyboard shortcuts - * without having to reset Mousetrap and rebind everything - * - * https://github.com/ccampbell/mousetrap/blob/master/plugins/pause/mousetrap-pause.js - */ -export default function(Mousetrap) { - var _originalStopCallback = Mousetrap.prototype.stopCallback; - - Mousetrap.prototype.stopCallback = function(e, element, combo) { - var self = this; - - if (self.paused) { - return true; - } - - return _originalStopCallback.call(self, e, element, combo); - }; - - Mousetrap.prototype.pause = function() { - var self = this; - self.paused = true; - }; - - Mousetrap.prototype.unpause = function() { - var self = this; - self.paused = false; - }; - - Mousetrap.init(); -} diff --git a/platform/ui/src/utils/hotkeys/recordPlugin.js b/platform/ui/src/utils/hotkeys/recordPlugin.js deleted file mode 100644 index 186964967..000000000 --- a/platform/ui/src/utils/hotkeys/recordPlugin.js +++ /dev/null @@ -1,218 +0,0 @@ -/** - * This extension allows you to record a sequence using Mousetrap. - * {@link https://craig.is/killing/mice} - * - * @author Dan Tao - */ -export default function (Mousetrap) { - /** - * the sequence currently being recorded - * - * @type {Array} - */ - var _recordedSequence = [], - /** - * a callback to invoke after recording a sequence - * - * @type {Function|null} - */ - _recordedSequenceCallback = null, - /** - * a list of all of the keys currently held down - * - * @type {Array} - */ - _currentRecordedKeys = [], - /** - * temporary state where we remember if we've already captured a - * character key in the current combo - * - * @type {boolean} - */ - _recordedCharacterKey = false, - /** - * a handle for the timer of the current recording - * - * @type {null|number} - */ - _recordTimer = null, - /** - * the original handleKey method to override when Mousetrap.record() is - * called - * - * @type {Function} - */ - _origHandleKey = Mousetrap.prototype.handleKey; - - /** - * handles a character key event - * - * @param {string} character - * @param {Array} modifiers - * @param {Event} e - * @returns void - */ - function _handleKey(character, modifiers, e) { - var self = this; - - if (!self.recording) { - _origHandleKey.apply(self, arguments); - return; - } - - // remember this character if we're currently recording a sequence - if (e.type == 'keydown') { - if (character.length === 1 && _recordedCharacterKey) { - _recordCurrentCombo(); - } - - for (let i = 0; i < modifiers.length; ++i) { - _recordKey(modifiers[i]); - } - _recordKey(character); - - // once a key is released, all keys that were held down at the time - // count as a keypress - } else if (e.type == 'keyup' && _currentRecordedKeys.length > 0) { - _recordCurrentCombo(); - } - } - - /** - * marks a character key as held down while recording a sequence - * - * @param {string} key - * @returns void - */ - function _recordKey(key) { - // one-off implementation of Array.indexOf, since IE6-9 don't support it - for (let i = 0; i < _currentRecordedKeys.length; ++i) { - if (_currentRecordedKeys[i] === key) { - return; - } - } - - _currentRecordedKeys.push(key); - - if (key.length === 1) { - _recordedCharacterKey = true; - } - } - - /** - * marks whatever key combination that's been recorded so far as finished - * and gets ready for the next combo - * - * @returns void - */ - function _recordCurrentCombo() { - _recordedSequence.push(_currentRecordedKeys); - _currentRecordedKeys = []; - _recordedCharacterKey = false; - _finishRecording(); - } - - /** - * ensures each combo in a sequence is in a predictable order and formats - * key combos to be '+'-delimited - * - * modifies the sequence in-place - * - * @param {Array} sequence - * @returns void - */ - function _normalizeSequence(sequence) { - for (let i = 0; i < sequence.length; ++i) { - sequence[i].sort(function (x, y) { - // modifier keys always come first, in alphabetical order - if (x.length > 1 && y.length === 1) { - return -1; - } else if (x.length === 1 && y.length > 1) { - return 1; - } - - // character keys come next (list should contain no duplicates, - // so no need for equality check) - return x > y ? 1 : -1; - }); - - sequence[i] = sequence[i].join('+'); - } - } - - /** - * finishes the current recording, passes the recorded sequence to the stored - * callback, and sets Mousetrap.handleKey back to its original function - * - * @returns void - */ - function _finishRecording() { - if (_recordedSequenceCallback) { - _normalizeSequence(_recordedSequence); - _recordedSequenceCallback(_recordedSequence); - } - - // reset all recorded state - _recordedSequence = []; - _recordedSequenceCallback = null; - _currentRecordedKeys = []; - } - - /** - * called to set a 1 second timeout on the current recording - * - * this is so after each key press in the sequence the recording will wait for - * 1 more second before executing the callback - * - * @returns void - */ - function _restartRecordTimer() { - clearTimeout(_recordTimer); - _recordTimer = setTimeout(_finishRecording, 1000); - } - - /** - * records the next sequence and passes it to a callback once it's - * completed - * - * @param {Function} callback - * @returns void - */ - Mousetrap.prototype.record = function (callback) { - var self = this; - self.recording = true; - _recordedSequenceCallback = function () { - self.recording = false; - callback.apply(self, arguments); - }; - }; - - /** - * stop recording - * - * @param {Function} callback - * @returns void - */ - Mousetrap.prototype.stopRecord = function () { - var self = this; - self.recording = false; - }; - - /** - * start recording - * - * @param {Function} callback - * @returns void - */ - Mousetrap.prototype.startRecording = function () { - var self = this; - self.recording = true; - }; - - Mousetrap.prototype.handleKey = function () { - var self = this; - _handleKey.apply(self, arguments); - }; - - Mousetrap.init(); -} diff --git a/platform/ui/src/utils/index.js b/platform/ui/src/utils/index.js deleted file mode 100644 index 8dc93b1ff..000000000 --- a/platform/ui/src/utils/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import getMockedStudies from './getMockedStudies'; -import hotkeys from './hotkeys'; - -const utils = { getMockedStudies, hotkeys }; - -export { getMockedStudies, hotkeys }; - -export default utils; diff --git a/platform/ui/src/views/StudyList/StudyList.js b/platform/ui/src/views/StudyList/StudyList.js deleted file mode 100644 index 3147d2782..000000000 --- a/platform/ui/src/views/StudyList/StudyList.js +++ /dev/null @@ -1,295 +0,0 @@ -/** - * THIS IS A TEMPORARY FILE -- SHOULD BE REMOVED - */ -import React, { useState } from 'react'; -import classnames from 'classnames'; -import moment from 'moment'; - -import { - EmptyStudies, - Icon, - StudyListExpandedRow, - Button, - StudyListPagination, - StudyListTable, - StudyListFilter, -} from '../../components'; -import utils from '../../utils'; - -// fix imports after refactor -import Header from './components/Header'; - -const filtersMeta = [ - { - name: 'patientName', - displayName: 'Patient Name', - inputType: 'Text', - isSortable: true, - gridCol: 4, - }, - { - name: 'mrn', - displayName: 'MRN', - inputType: 'Text', - isSortable: true, - gridCol: 2, - }, - { - name: 'studyDate', - displayName: 'Study date', - inputType: 'DateRange', - isSortable: true, - gridCol: 5, - }, - { - name: 'description', - displayName: 'Description', - inputType: 'Text', - isSortable: true, - gridCol: 4, - }, - { - name: 'modality', - displayName: 'Modality', - inputType: 'MultiSelect', - inputProps: { - options: [ - { value: 'SEG', label: 'SEG' }, - { value: 'CT', label: 'CT' }, - { value: 'MR', label: 'MR' }, - { value: 'SR', label: 'SR' }, - ], - }, - isSortable: true, - gridCol: 3, - }, - { - name: 'accession', - displayName: 'Accession', - inputType: 'Text', - isSortable: true, - gridCol: 4, - }, - { - name: 'instances', - displayName: 'Instances', - inputType: 'None', - isSortable: true, - gridCol: 2, - }, -]; - -const defaultFilterValues = { - patientName: '', - mrn: '', - studyDate: { - startDate: null, - endDate: null, - }, - description: '', - modality: undefined, - accession: '', - sortBy: '', - sortDirection: 'none', - page: 0, - resultsPerPage: 25, -}; - -const isFiltering = (filterValues, defaultFilterValues) => { - return Object.keys(defaultFilterValues).some(name => { - return filterValues[name] !== defaultFilterValues[name]; - }); -}; - -const StudyList = () => { - const [filterValues, setFilterValues] = useState(defaultFilterValues); - const studies = utils.getMockedStudies(); - const numOfStudies = studies.length; - const [expandedRows, setExpandedRows] = useState([]); - - const tableDataSource = studies.map((study, key) => { - const rowKey = key + 1; - const isExpanded = expandedRows.some(k => k === rowKey); - const { - AccessionNumber, - Modalities, - Instances, - StudyDescription, - PatientId, - PatientName, - StudyDate, - series, - } = study; - - const seriesTableColumns = { - description: 'Description', - seriesNumber: 'Series', - modality: 'Modality', - Instances: 'Instances', - }; - - const seriesTableDataSource = series.map(seriesItem => { - const { SeriesNumber, Modality, instances } = seriesItem; - return { - description: 'Patient Protocol', - seriesNumber: SeriesNumber, - modality: Modality, - Instances: instances.length, - }; - }); - - return { - row: [ - { - key: 'patientName', - content: PatientName, - gridCol: 4, - }, - { - key: 'mrn', - content: PatientId, - gridCol: 2, - }, - { - key: 'studyDate', - content: ( -
- - {moment(StudyDate).format('MMM-DD-YYYY')} - - {moment(StudyDate).format('hh:mm A')} -
- ), - gridCol: 5, - }, - { - key: 'description', - content: StudyDescription, - gridCol: 4, - }, - { - key: 'modality', - content: Modalities, - gridCol: 3, - }, - { - key: 'accession', - content: AccessionNumber, - gridCol: 4, - }, - { - key: 'instances', - content: ( - <> - - {Instances} - - ), - gridCol: 4, - }, - ], - expandedContent: ( - - - - -
- - Feedback text lorem ipsum dolor sit amet -
-
- ), - onClickRow: () => - setExpandedRows(s => - isExpanded ? s.filter(n => rowKey !== n) : [...s, rowKey] - ), - isExpanded, - }; - }); - - const [currentPage, setCurrentPage] = useState(1); - const [perPage, setPerPage] = useState(25); - const totalPages = Math.floor(numOfStudies / perPage); - const onChangePage = page => { - if (page > totalPages) { - return; - } - setCurrentPage(page); - }; - const onChangePerPage = perPage => { - setPerPage(perPage); - setCurrentPage(1); - }; - - const hasStudies = numOfStudies > 0; - - return ( -
-
- setFilterValues(defaultFilterValues)} - isFiltering={isFiltering(filterValues, defaultFilterValues)} - /> - - {hasStudies ? ( - <> - - - - ) : ( -
- -
- )} -
- ); -}; - -export default StudyList; diff --git a/platform/viewer/src/routes/WorkList/WorkList.jsx b/platform/viewer/src/routes/WorkList/WorkList.jsx index d2dd7dec2..731735384 100644 --- a/platform/viewer/src/routes/WorkList/WorkList.jsx +++ b/platform/viewer/src/routes/WorkList/WorkList.jsx @@ -12,6 +12,8 @@ import { useAppConfig } from '@state'; import { useDebounce, useQuery } from '@hooks'; import { utils } from '@ohif/core'; +const { sortBySeriesDate, hotkeys } = utils; + import { Icon, StudyListExpandedRow, @@ -194,7 +196,7 @@ function WorkList({ const series = await dataSource.query.series.search(studyInstanceUid); seriesInStudiesMap.set( studyInstanceUid, - utils.sortBySeriesDate(series) + sortBySeriesDate(series) ); setStudiesWithSeriesData([...studiesWithSeriesData, studyInstanceUid]); } catch (ex) { @@ -399,6 +401,7 @@ function WorkList({ hide(); }, onReset: () => hotkeysManager.restoreDefaultBindings(), + hotkeysModule: hotkeys }, }), }, diff --git a/yarn.lock b/yarn.lock index 80d75a49f..e29c84a8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1114,27 +1114,13 @@ core-js-pure "^3.15.0" regenerator-runtime "^0.13.4" -"@babel/runtime@7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.2.tgz#81c89935f4647706fc54541145e6b4ecfef4b8e3" - integrity sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg== - dependencies: - regenerator-runtime "^0.12.0" - -"@babel/runtime@7.7.6", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6": +"@babel/runtime@7.1.2", "@babel/runtime@7.7.6", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.7.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f" integrity sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw== dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d" - integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg== - dependencies: - regenerator-runtime "^0.13.4" - "@babel/template@^7.12.7", "@babel/template@^7.14.5", "@babel/template@^7.4.0": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -15604,11 +15590,6 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.12.0: - version "0.12.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" - integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== - regenerator-runtime@^0.13.1, regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"