diff --git a/.vscode/settings.json b/.vscode/settings.json index 6d87c6be1..b9d598ba3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,5 +28,8 @@ ], "prettier.disableLanguages": ["html"], "prettier.endOfLine": "lf", - "workbench.colorCustomizations": {} + "workbench.colorCustomizations": {}, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + } } diff --git a/docs/latest/extensions/modules/panel.md b/docs/latest/extensions/modules/panel.md index 57b63719a..6254824b5 100644 --- a/docs/latest/extensions/modules/panel.md +++ b/docs/latest/extensions/modules/panel.md @@ -40,6 +40,10 @@ export default { from: 'right', // The target component to toggle open/close target: 'target-component-id', + // UI Hint; If the target panel is in a "disabled" state + isDisabled: studies => { + return false; + }, // Overrides `defaultContext`, if specified context: ['ACTIVE_VIEWPORT:MAGIC'], }, diff --git a/extensions/_example/src/index.js b/extensions/_example/src/index.js index bafd2ae32..de0d09128 100644 --- a/extensions/_example/src/index.js +++ b/extensions/_example/src/index.js @@ -21,7 +21,6 @@ export default { /** * MODULE GETTERS */ - getViewportModule() { return '... react component ...'; }, @@ -98,6 +97,9 @@ const panelModule = { icon: 'th-list', label: 'Segments', target: 'segment-panel', + isDisabled: studies => { + return false; + }, }, ], components: [ diff --git a/platform/viewer/CHANGELOG.md b/platform/viewer/CHANGELOG.md index da09b1211..13205856d 100644 --- a/platform/viewer/CHANGELOG.md +++ b/platform/viewer/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.7.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.7.4...@ohif/viewer@3.7.5) (2020-03-05) + +**Note:** Version bump only for package @ohif/viewer + + + + + ## [3.7.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.7.3...@ohif/viewer@3.7.4) (2020-03-03) **Note:** Version bump only for package @ohif/viewer diff --git a/platform/viewer/package.json b/platform/viewer/package.json index f2d58efd0..4448c0699 100644 --- a/platform/viewer/package.json +++ b/platform/viewer/package.json @@ -1,6 +1,6 @@ { "name": "@ohif/viewer", - "version": "3.7.4", + "version": "3.7.5", "description": "OHIF Viewer", "author": "OHIF Contributors", "license": "MIT", diff --git a/platform/viewer/src/connectedComponents/ToolbarRow.js b/platform/viewer/src/connectedComponents/ToolbarRow.js index 29ba3798f..86839fe07 100644 --- a/platform/viewer/src/connectedComponents/ToolbarRow.js +++ b/platform/viewer/src/connectedComponents/ToolbarRow.js @@ -25,9 +25,17 @@ class ToolbarRow extends Component { isRightSidePanelOpen: PropTypes.bool.isRequired, selectedLeftSidePanel: PropTypes.string.isRequired, selectedRightSidePanel: PropTypes.string.isRequired, - handleSidePanelChange: PropTypes.func, + handleSidePanelChange: PropTypes.func.isRequired, activeContexts: PropTypes.arrayOf(PropTypes.string).isRequired, studies: PropTypes.array, + t: PropTypes.func.isRequired, + // NOTE: withDialog, withModal HOCs + dialog: PropTypes.any, + modal: PropTypes.any, + }; + + static defaultProps = { + studies: [], }; constructor(props) { @@ -50,30 +58,30 @@ class ToolbarRow extends Component { this._handleBuiltIn = _handleBuiltIn.bind(this); const panelModules = extensionManager.modules[MODULE_TYPES.PANEL]; + this.buttonGroups = { - left: [ - // TODO: This should come from extensions, instead of being baked in - { - value: 'studies', - icon: 'th-large', - bottomLabel: this.props.t('Series'), - }, - ], + left: [], right: [], }; + // ~ FIND MENU OPTIONS panelModules.forEach(panelExtension => { const panelModule = panelExtension.module; const defaultContexts = Array.from(panelModule.defaultContext); - // MENU OPTIONS panelModule.menuOptions.forEach(menuOption => { const contexts = Array.from(menuOption.context || defaultContexts); - - const activeContextIncludesAnyPanelContexts = this.props.activeContexts.some( - actx => contexts.includes(actx) + const hasActiveContext = this.props.activeContexts.some(actx => + contexts.includes(actx) ); - if (activeContextIncludesAnyPanelContexts) { + + // It's a bit beefy to pass studies; probably only need to be reactive on `studyInstanceUIDs` and activeViewport? + // Note: This does not cleanly handle `studies` prop updating with panel open + const isDisabled = + typeof menuOption.isDisabled === 'function' && + menuOption.isDisabled(this.props.studies); + + if (hasActiveContext && !isDisabled) { const menuOptionEntry = { value: menuOption.target, icon: menuOption.icon, @@ -85,6 +93,13 @@ class ToolbarRow extends Component { } }); }); + + // TODO: This should come from extensions, instead of being baked in + this.buttonGroups.left.unshift({ + value: 'studies', + icon: 'th-large', + bottomLabel: this.props.t('Series'), + }); } componentDidUpdate(prevProps) { @@ -222,6 +237,10 @@ function _getButtonComponents(toolbarButtons, activeButtons) { } /** + * TODO: DEPRECATE + * This is used exclusively in `extensions/cornerstone/src` + * We have better ways with new UI Services to trigger "builtin" behaviors + * * A handy way for us to handle different button types. IE. firing commands for * buttons, or initiation built in behavior. * @@ -273,7 +292,7 @@ function _getVisibleToolbarButtons() { function _handleBuiltIn(button) { /* TODO: Keep cine button active until its unselected. */ - const { dialog, modal, t } = this.props; + const { dialog, t } = this.props; const { dialogId } = this.state; const { id, options } = button; diff --git a/platform/viewer/src/connectedComponents/Viewer.js b/platform/viewer/src/connectedComponents/Viewer.js index 922b5660c..ad8ff6790 100644 --- a/platform/viewer/src/connectedComponents/Viewer.js +++ b/platform/viewer/src/connectedComponents/Viewer.js @@ -18,45 +18,30 @@ import WhiteLabellingContext from '../context/WhiteLabellingContext.js'; import UserManagerContext from '../context/UserManagerContext'; import './Viewer.css'; -/** - * Inits OHIF Hanging Protocol's onReady. - * It waits for OHIF Hanging Protocol to be ready to instantiate the ProtocolEngine - * Hanging Protocol will use OHIF LayoutManager to render viewports properly - */ -/*const initHangingProtocol = () => { - // When Hanging Protocol is ready - HP.ProtocolStore.onReady(() => { - - // Gets all StudyMetadata objects: necessary for Hanging Protocol to access study metadata - const studyMetadataList = OHIF.viewer.StudyMetadataList.all(); - - // Instantiate StudyMetadataSource: necessary for Hanging Protocol to get study metadata - const studyMetadataSource = new OHIF.studies.classes.OHIFStudyMetadataSource(); - - // Get prior studies map - const studyPriorsMap = OHIF.studylist.functions.getStudyPriorsMap(studyMetadataList); - - // Creates Protocol Engine object with required arguments - const ProtocolEngine = new HP.ProtocolEngine(layoutManager, studyMetadataList, studyPriorsMap, studyMetadataSource); - - // Sets up Hanging Protocol engine - HP.setEngine(ProtocolEngine); - }); -};*/ - -/*const viewportUtils = OHIF.viewerbase.viewportUtils; - -OHIF.viewer.functionList = { - toggleCineDialog: viewportUtils.toggleCineDialog, - toggleCinePlay: viewportUtils.toggleCinePlay, - clearTools: viewportUtils.clearTools, - resetViewport: viewportUtils.resetViewport, - invert: viewportUtils.invert -};*/ class Viewer extends Component { static propTypes = { - studies: PropTypes.array, + studies: PropTypes.arrayOf( + PropTypes.shape({ + studyInstanceUid: PropTypes.string.isRequired, + studyDate: PropTypes.string, + displaySets: PropTypes.arrayOf( + PropTypes.shape({ + displaySetInstanceUid: PropTypes.string.isRequired, + seriesDescription: PropTypes.string, + seriesNumber: PropTypes.number, + instanceNumber: PropTypes.number, + numImageFrames: PropTypes.number, + modality: PropTypes.string.isRequired, + images: PropTypes.arrayOf( + PropTypes.shape({ + getImageId: PropTypes.func.isRequired, + }) + ), + }) + ), + }) + ), studyInstanceUids: PropTypes.array, activeServer: PropTypes.shape({ type: PropTypes.string,