From 0dd7fdb81ad884d7e719e8777900399d29b4bfb4 Mon Sep 17 00:00:00 2001 From: IbrahimCSAE Date: Thu, 14 Mar 2024 04:20:03 -0400 Subject: [PATCH 1/3] worklist updates --- platform/app/src/routes/WorkList/WorkList.tsx | 32 +++++++++++++++---- platform/ui/src/assets/icons/launch-arrow.svg | 6 ++-- platform/ui/src/assets/icons/launch-info.svg | 9 +++--- platform/ui/src/components/Button/Button.tsx | 10 ++++-- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/platform/app/src/routes/WorkList/WorkList.tsx b/platform/app/src/routes/WorkList/WorkList.tsx index ae518a29611..db022c83c8f 100644 --- a/platform/app/src/routes/WorkList/WorkList.tsx +++ b/platform/app/src/routes/WorkList/WorkList.tsx @@ -27,6 +27,8 @@ import { UserPreferences, LoadingIndicatorProgress, useSessionStorage, + Button, + ButtonEnums, } from '@ohif/ui'; import i18n from '@ohif/i18n'; @@ -254,11 +256,13 @@ function WorkList({ const studyDate = date && moment(date, ['YYYYMMDD', 'YYYY.MM.DD'], true).isValid() && - moment(date, ['YYYYMMDD', 'YYYY.MM.DD']).format(t('Common:localDateFormat','MMM-DD-YYYY')); + moment(date, ['YYYYMMDD', 'YYYY.MM.DD']).format(t('Common:localDateFormat', 'MMM-DD-YYYY')); const studyTime = time && moment(time, ['HH', 'HHmm', 'HHmmss', 'HHmmss.SSS']).isValid() && - moment(time, ['HH', 'HHmm', 'HHmmss', 'HHmmss.SSS']).format(t('Common:localTimeFormat', 'hh:mm A')); + moment(time, ['HH', 'HHmm', 'HHmmss', 'HHmmss.SSS']).format( + t('Common:localTimeFormat', 'hh:mm A') + ); return { dataCY: `studyRow-${studyInstanceUid}`, @@ -382,16 +386,30 @@ function WorkList({ // to={`${mode.routeName}/dicomweb?StudyInstanceUIDs=${studyInstanceUid}`} > {/* TODO revisit the completely rounded style of buttons used for launching a mode from the worklist later - for now use LegacyButton*/} - } // launch-arrow | launch-info + tooltip={ + !isValidMode ? ( +
+ This study does not contain modalities supported by {mode.displayName}{' '} + mode +
+ ) : null + } + startIcon={ + + } // launch-arrow | launch-info onClick={() => {}} data-cy={`mode-${mode.routeName}-${studyInstanceUid}`} + className={isValidMode ? 'text-[13px]' : 'bg-[#222d44] text-[13px]'} > {mode.displayName} -
+ ) ); diff --git a/platform/ui/src/assets/icons/launch-arrow.svg b/platform/ui/src/assets/icons/launch-arrow.svg index da4b7827f9c..0f55172d878 100644 --- a/platform/ui/src/assets/icons/launch-arrow.svg +++ b/platform/ui/src/assets/icons/launch-arrow.svg @@ -1,7 +1,7 @@ - - - + + + diff --git a/platform/ui/src/assets/icons/launch-info.svg b/platform/ui/src/assets/icons/launch-info.svg index f4f14e4c88a..6e999dc3575 100644 --- a/platform/ui/src/assets/icons/launch-info.svg +++ b/platform/ui/src/assets/icons/launch-info.svg @@ -1,7 +1,8 @@ - - - - + + + + + diff --git a/platform/ui/src/components/Button/Button.tsx b/platform/ui/src/components/Button/Button.tsx index fb13927c608..39e4931163b 100644 --- a/platform/ui/src/components/Button/Button.tsx +++ b/platform/ui/src/components/Button/Button.tsx @@ -2,6 +2,7 @@ import React, { useRef } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import * as ButtonEnums from './ButtonEnums'; +import Tooltip from '../Tooltip/Tooltip'; const sizeClasses = { [ButtonEnums.size.small]: 'h-[26px] text-[13px]', @@ -66,11 +67,12 @@ const Button = ({ name, className, onClick, + tooltip = null, }) => { const startIcon = startIconProp && ( <> {React.cloneElement(startIconProp, { - className: classnames('w-4 h-4 fill-current'), + className: classnames('w-4 h-4 fill-current', startIconProp?.props?.className), })} ); @@ -78,7 +80,7 @@ const Button = ({ const endIcon = endIconProp && ( <> {React.cloneElement(endIconProp, { - className: classnames('w-4 h-4 fill-current'), + className: classnames('w-4 h-4 fill-current', endIconProp?.props?.className), })} ); @@ -108,7 +110,7 @@ const Button = ({ onClick={handleOnClick} data-cy={`${name}-btn`} > - {startIcon} + {tooltip ? {startIcon} : startIcon} {children} {endIcon} @@ -141,6 +143,8 @@ Button.propTypes = { endIcon: PropTypes.node, /** Additional TailwindCSS classnames */ className: PropTypes.string, + /** Tooltip for the button */ + tooltip: PropTypes.node, }; export default Button; From 9cbd70979e293c3385210756750f69b4510df025 Mon Sep 17 00:00:00 2001 From: IbrahimCSAE Date: Thu, 14 Mar 2024 04:28:36 -0400 Subject: [PATCH 2/3] hide modals and dialogs on mode exit --- modes/basic-dev-mode/src/index.js | 11 +++++++++-- modes/basic-test-mode/src/index.ts | 4 ++++ modes/longitudinal/src/index.js | 4 ++++ modes/microscopy/src/index.tsx | 4 +++- modes/segmentation/src/index.tsx | 4 ++++ modes/tmtv/src/index.js | 4 ++++ platform/cli/templates/mode/src/index.tsx | 4 ++++ 7 files changed, 32 insertions(+), 3 deletions(-) diff --git a/modes/basic-dev-mode/src/index.js b/modes/basic-dev-mode/src/index.js index 01513492fea..c252265909f 100644 --- a/modes/basic-dev-mode/src/index.js +++ b/modes/basic-dev-mode/src/index.js @@ -133,8 +133,15 @@ function modeFactory({ modeConfiguration }) { ]); }, onModeExit: ({ servicesManager }) => { - const { toolGroupService, measurementService, toolbarService } = servicesManager.services; - + const { + toolGroupService, + measurementService, + toolbarService, + uiDialogService, + uiModalService, + } = servicesManager.services; + uiDialogService.dismissAll(); + uiModalService.hide(); toolGroupService.destroy(); }, validationTags: { diff --git a/modes/basic-test-mode/src/index.ts b/modes/basic-test-mode/src/index.ts index 1c434217936..64a607d9a09 100644 --- a/modes/basic-test-mode/src/index.ts +++ b/modes/basic-test-mode/src/index.ts @@ -143,8 +143,12 @@ function modeFactory() { syncGroupService, segmentationService, cornerstoneViewportService, + uiDialogService, + uiModalService, } = servicesManager.services; + uiDialogService.dismissAll(); + uiModalService.hide(); toolGroupService.destroy(); syncGroupService.destroy(); segmentationService.destroy(); diff --git a/modes/longitudinal/src/index.js b/modes/longitudinal/src/index.js index 0d9be56af58..1052cbfd8e9 100644 --- a/modes/longitudinal/src/index.js +++ b/modes/longitudinal/src/index.js @@ -179,11 +179,15 @@ function modeFactory({ modeConfiguration }) { toolbarService, segmentationService, cornerstoneViewportService, + uiDialogService, + uiModalService, } = servicesManager.services; _activatePanelTriggersSubscriptions.forEach(sub => sub.unsubscribe()); _activatePanelTriggersSubscriptions = []; + uiDialogService.dismissAll(); + uiModalService.hide(); toolGroupService.destroy(); syncGroupService.destroy(); segmentationService.destroy(); diff --git a/modes/microscopy/src/index.tsx b/modes/microscopy/src/index.tsx index 7165b7cc39c..d9ed5b54d41 100644 --- a/modes/microscopy/src/index.tsx +++ b/modes/microscopy/src/index.tsx @@ -56,8 +56,10 @@ function modeFactory({ modeConfiguration }) { }, onModeExit: ({ servicesManager }) => { - const { toolbarService } = servicesManager.services; + const { toolbarService, uiDialogService, uiModalService } = servicesManager.services; + uiDialogService.dismissAll(); + uiModalService.hide(); toolbarService.reset(); }, diff --git a/modes/segmentation/src/index.tsx b/modes/segmentation/src/index.tsx index 8b24196f161..446f45b5666 100644 --- a/modes/segmentation/src/index.tsx +++ b/modes/segmentation/src/index.tsx @@ -106,8 +106,12 @@ function modeFactory({ modeConfiguration }) { toolbarService, segmentationService, cornerstoneViewportService, + uiDialogService, + uiModalService, } = servicesManager.services; + uiDialogService.dismissAll(); + uiModalService.hide(); toolGroupService.destroy(); syncGroupService.destroy(); segmentationService.destroy(); diff --git a/modes/tmtv/src/index.js b/modes/tmtv/src/index.js index dd57be35e06..7796fae6caa 100644 --- a/modes/tmtv/src/index.js +++ b/modes/tmtv/src/index.js @@ -165,9 +165,13 @@ function modeFactory({ modeConfiguration }) { syncGroupService, segmentationService, cornerstoneViewportService, + uiDialogService, + uiModalService, } = servicesManager.services; unsubscriptions.forEach(unsubscribe => unsubscribe()); + uiDialogService.dismissAll(); + uiModalService.hide(); toolGroupService.destroy(); syncGroupService.destroy(); segmentationService.destroy(); diff --git a/platform/cli/templates/mode/src/index.tsx b/platform/cli/templates/mode/src/index.tsx index 55be0603939..e129a9a05d7 100644 --- a/platform/cli/templates/mode/src/index.tsx +++ b/platform/cli/templates/mode/src/index.tsx @@ -98,8 +98,12 @@ function modeFactory({ modeConfiguration }) { toolbarService, segmentationService, cornerstoneViewportService, + uiDialogService, + uiModalService, } = servicesManager.services; + uiDialogService.dismissAll(); + uiModalService.hide(); toolGroupService.destroy(); syncGroupService.destroy(); segmentationService.destroy(); From 4c079c637e0614c1d48ec192d9c658ba49662bac Mon Sep 17 00:00:00 2001 From: IbrahimCSAE Date: Mon, 18 Mar 2024 20:11:50 -0400 Subject: [PATCH 3/3] finalized --- modes/basic-dev-mode/src/index.js | 5 +++- modes/basic-test-mode/src/index.ts | 8 +++++-- modes/longitudinal/src/index.js | 8 +++++-- modes/microscopy/src/index.tsx | 6 +++-- modes/segmentation/src/index.tsx | 7 +++--- modes/tmtv/src/index.js | 5 +++- platform/app/public/config/default.js | 1 + platform/app/src/routes/WorkList/WorkList.tsx | 23 +++++++++++++++---- platform/ui/src/components/Button/Button.tsx | 13 +++++++---- .../StudyListTable/StudyListTableRow.tsx | 2 +- 10 files changed, 55 insertions(+), 23 deletions(-) diff --git a/modes/basic-dev-mode/src/index.js b/modes/basic-dev-mode/src/index.js index c252265909f..bcedc4aca8f 100644 --- a/modes/basic-dev-mode/src/index.js +++ b/modes/basic-dev-mode/src/index.js @@ -152,7 +152,10 @@ function modeFactory({ modeConfiguration }) { const modalities_list = modalities.split('\\'); // Slide Microscopy modality not supported by basic mode yet - return !modalities_list.includes('SM'); + return { + valid: !modalities_list.includes('SM'), + description: 'The mode does not support the following modalities: SM', + }; }, routes: [ { diff --git a/modes/basic-test-mode/src/index.ts b/modes/basic-test-mode/src/index.ts index 64a607d9a09..a6e9d0827ad 100644 --- a/modes/basic-test-mode/src/index.ts +++ b/modes/basic-test-mode/src/index.ts @@ -163,8 +163,12 @@ function modeFactory() { const modalities_list = modalities.split('\\'); // Exclude non-image modalities - return !!modalities_list.filter(modality => NON_IMAGE_MODALITIES.indexOf(modality) === -1) - .length; + return { + valid: !!modalities_list.filter(modality => NON_IMAGE_MODALITIES.indexOf(modality) === -1) + .length, + description: + 'The mode does not support studies that ONLY include the following modalities: SM, ECG, SR, SEG', + }; }, routes: [ { diff --git a/modes/longitudinal/src/index.js b/modes/longitudinal/src/index.js index 1052cbfd8e9..571d6a5f69e 100644 --- a/modes/longitudinal/src/index.js +++ b/modes/longitudinal/src/index.js @@ -202,8 +202,12 @@ function modeFactory({ modeConfiguration }) { const modalities_list = modalities.split('\\'); // Exclude non-image modalities - return !!modalities_list.filter(modality => NON_IMAGE_MODALITIES.indexOf(modality) === -1) - .length; + return { + valid: !!modalities_list.filter(modality => NON_IMAGE_MODALITIES.indexOf(modality) === -1) + .length, + description: + 'The mode does not support studies that ONLY include the following modalities: SM, ECG, SR, SEG, RTSTRUCT', + }; }, routes: [ { diff --git a/modes/microscopy/src/index.tsx b/modes/microscopy/src/index.tsx index d9ed5b54d41..557ec00d03b 100644 --- a/modes/microscopy/src/index.tsx +++ b/modes/microscopy/src/index.tsx @@ -71,8 +71,10 @@ function modeFactory({ modeConfiguration }) { isValidMode: ({ modalities }) => { const modalities_list = modalities.split('\\'); - // Slide Microscopy and ECG modality not supported by basic mode yet - return modalities_list.includes('SM'); + return { + valid: modalities_list.includes('SM'), + description: 'Microscopy mode only supports the SM modality', + }; }, routes: [ diff --git a/modes/segmentation/src/index.tsx b/modes/segmentation/src/index.tsx index 446f45b5666..57b46c60357 100644 --- a/modes/segmentation/src/index.tsx +++ b/modes/segmentation/src/index.tsx @@ -131,11 +131,10 @@ function modeFactory({ modeConfiguration }) { // Don't show the mode if the selected studies have only one modality // that is not supported by the mode const modalitiesArray = modalities.split('\\'); - if (modalitiesArray.length === 1) { - return !['SM', 'US', 'MG', 'OT', 'DOC', 'CR'].includes(modalitiesArray[0]); + return { + valid: modalitiesArray.length === 1 ? !['SM', 'US', 'MG', 'OT', 'DOC', 'CR'].includes(modalitiesArray[0]) : true, + description: 'The mode does not support studies that ONLY include the following modalities: SM, US, MG, OT, DOC, CR', } - - return true; }, /** * Mode Routes are used to define the mode's behavior. A list of Mode Route diff --git a/modes/tmtv/src/index.js b/modes/tmtv/src/index.js index 7796fae6caa..b21a375828c 100644 --- a/modes/tmtv/src/index.js +++ b/modes/tmtv/src/index.js @@ -197,7 +197,10 @@ function modeFactory({ modeConfiguration }) { study.studyInstanceUid !== '1.3.6.1.4.1.12842.1.1.14.3.20220915.105557.468.2963630849'; // there should be both CT and PT modalities and the modality should not be SM - return isValid; + return { + valid: isValid, + description: 'The mode requires both PT and CT series in the study', + }; }, routes: [ { diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index 00013529ea8..88f7b872e12 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -12,6 +12,7 @@ window.config = { showCPUFallbackMessage: true, showLoadingIndicator: true, strictZSpacingForVolumeViewport: true, + groupEnabledModesFirst: true, maxNumRequests: { interaction: 100, thumbnail: 75, diff --git a/platform/app/src/routes/WorkList/WorkList.tsx b/platform/app/src/routes/WorkList/WorkList.tsx index db022c83c8f..50cfccf2961 100644 --- a/platform/app/src/routes/WorkList/WorkList.tsx +++ b/platform/app/src/routes/WorkList/WorkList.tsx @@ -350,10 +350,24 @@ function WorkList({ } >
- {appConfig.loadedModes.map((mode, i) => { + {(appConfig.groupEnabledModesFirst + ? appConfig.loadedModes.sort((a, b) => { + const isValidA = a.isValidMode({ + modalities: modalities.replaceAll('/', '\\'), + study, + }).valid; + const isValidB = b.isValidMode({ + modalities: modalities.replaceAll('/', '\\'), + study, + }).valid; + + return isValidB - isValidA; + }) + : appConfig.loadedModes + ).map((mode, i) => { const modalitiesToCheck = modalities.replaceAll('/', '\\'); - const isValidMode = mode.isValidMode({ + const { valid: isValidMode, description: invalidModeDescription } = mode.isValidMode({ modalities: modalitiesToCheck, study, }); @@ -390,11 +404,10 @@ function WorkList({ type={ButtonEnums.type.primary} size={ButtonEnums.size.medium} disabled={!isValidMode} - tooltip={ + startIconTooltip={ !isValidMode ? (
- This study does not contain modalities supported by {mode.displayName}{' '} - mode + {invalidModeDescription}
) : null } diff --git a/platform/ui/src/components/Button/Button.tsx b/platform/ui/src/components/Button/Button.tsx index 39e4931163b..b1e750c5cb7 100644 --- a/platform/ui/src/components/Button/Button.tsx +++ b/platform/ui/src/components/Button/Button.tsx @@ -67,7 +67,8 @@ const Button = ({ name, className, onClick, - tooltip = null, + startIconTooltip = null, + endIconTooltip = null, }) => { const startIcon = startIconProp && ( <> @@ -110,9 +111,9 @@ const Button = ({ onClick={handleOnClick} data-cy={`${name}-btn`} > - {tooltip ? {startIcon} : startIcon} + {startIconTooltip ? {startIcon} : startIcon} {children} - {endIcon} + {endIconTooltip ? {endIcon} : endIcon} ); }; @@ -143,8 +144,10 @@ Button.propTypes = { endIcon: PropTypes.node, /** Additional TailwindCSS classnames */ className: PropTypes.string, - /** Tooltip for the button */ - tooltip: PropTypes.node, + /** Tooltip for the start icon */ + startIconTooltip: PropTypes.node, + /** Tooltip for the end icon */ + endIconTooltip: PropTypes.node, }; export default Button; diff --git a/platform/ui/src/components/StudyListTable/StudyListTableRow.tsx b/platform/ui/src/components/StudyListTable/StudyListTableRow.tsx index 2235f277d1c..4a3fa6f9316 100644 --- a/platform/ui/src/components/StudyListTable/StudyListTableRow.tsx +++ b/platform/ui/src/components/StudyListTable/StudyListTableRow.tsx @@ -23,7 +23,7 @@ const StudyListTableRow = props => { className={classnames( 'w-full transition duration-300', { - 'border-primary-light hover:border-secondary-light mb-2 overflow-hidden rounded border': + 'border-primary-light hover:border-secondary-light mb-2 overflow-visible rounded border': isExpanded, }, {