Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(thumbnail highlight): Thumbnails of hydrated series are now highlighted #3594

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import CornerstoneOverlays from './Overlays/CornerstoneOverlays';
import getSOPInstanceAttributes from '../utils/measurementServiceMappings/utils/getSOPInstanceAttributes';
import CornerstoneServices from '../types/CornerstoneServices';
import CinePlayer from '../components/CinePlayer';
import { Types } from '@ohif/core';

const STACK = 'stack';

Expand Down Expand Up @@ -264,7 +265,14 @@ const OHIFCornerstoneViewport = React.memo(props => {
useEffect(() => {
const { unsubscribe } = displaySetService.subscribe(
displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED,
async invalidatedDisplaySetInstanceUID => {
async ({
displaySetInstanceUID: invalidatedDisplaySetInstanceUID,
invalidateData,
}: Types.DisplaySetSeriesMetadataInvalidatedEvent) => {
if (!invalidateData) {
return;
}

const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
viewportIndex
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,8 @@ class SegmentationService extends PubSubService {
);
}

this._setDisplaySetIsHydrated(segmentationId, true);

segmentation.hydrated = true;

if (!suppressEvents) {
Expand All @@ -1132,6 +1134,18 @@ class SegmentationService extends PubSubService {
}
};

private _setDisplaySetIsHydrated(
displaySetUID: string,
isHydrated: boolean
): void {
const {
DisplaySetService: displaySetService,
} = this.servicesManager.services;
const displaySet = displaySetService.getDisplaySetByUID(displaySetUID);
displaySet.isHydrated = isHydrated;
displaySetService.setDisplaySetMetadataInvalidated(displaySetUID, false);
}

private _highlightLabelmap(
segmentIndex: number,
alpha: number,
Expand Down Expand Up @@ -1303,6 +1317,8 @@ class SegmentationService extends PubSubService {
}
}

this._setDisplaySetIsHydrated(segmentationId, false);

this._broadcastEvent(this.EVENTS.SEGMENTATION_REMOVED, {
segmentationId,
});
Expand Down
14 changes: 14 additions & 0 deletions extensions/default/src/Panels/PanelStudyBrowser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,22 @@ function PanelStudyBrowser({
}
);

const SubscriptionDisplaySetMetaDataInvalidated = displaySetService.subscribe(
displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED,
() => {
const mappedDisplaySets = _mapDisplaySets(
displaySetService.getActiveDisplaySets(),
thumbnailImageSrcMap
);

setDisplaySets(mappedDisplaySets);
}
);

return () => {
SubscriptionDisplaySetsAdded.unsubscribe();
SubscriptionDisplaySetsChanged.unsubscribe();
SubscriptionDisplaySetMetaDataInvalidated.unsubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
Expand Down Expand Up @@ -325,6 +338,7 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
displaySetInstanceUID: ds.displaySetInstanceUID,
// .. Any other data to pass
},
isHydratedForDerivedDisplaySet: ds.isHydrated,
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,29 @@ function PanelStudyBrowserTracking({
}
);

const SubscriptionDisplaySetMetaDataInvalidated = displaySetService.subscribe(
displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should add the same logic to the PanelStudyBrowswer too

() => {
const mappedDisplaySets = _mapDisplaySets(
displaySetService.getActiveDisplaySets(),
thumbnailImageSrcMap,
trackedSeries,
viewports,
viewportGridService,
dataSource,
displaySetService,
uiDialogService,
uiNotificationService
);

setDisplaySets(mappedDisplaySets);
}
);

return () => {
SubscriptionDisplaySetsAdded.unsubscribe();
SubscriptionDisplaySetsChanged.unsubscribe();
SubscriptionDisplaySetMetaDataInvalidated.unsubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
Expand Down Expand Up @@ -459,6 +479,7 @@ function _mapDisplaySets(
// .. Any other data to pass
},
isTracked: trackedSeriesInstanceUIDs.includes(ds.SeriesInstanceUID),
isHydratedForDerivedDisplaySet: ds.isHydrated,
viewportIdentificator,
};

Expand Down
23 changes: 9 additions & 14 deletions platform/core/src/services/DisplaySetService/DisplaySetService.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { ExtensionManager } from '../../extensions';
import { InstanceMetadata } from '../../types';
import { DisplaySet, InstanceMetadata } from '../../types';
import { PubSubService } from '../_shared/pubSubServiceInterface';
import EVENTS from './EVENTS';

export type DisplaySet = {
displaySetInstanceUID: string;
instances: InstanceMetadata[];
StudyInstanceUID: string;
SeriesInstanceUID?: string;
numImages?: number;
};

const displaySetCache = new Map<string, DisplaySet>();

/**
Expand Down Expand Up @@ -142,18 +134,21 @@ export default class DisplaySetService extends PubSubService {
return displaySet;
}

public setDisplaySetMetadataInvalidated(displaySetInstanceUID: string): void {
public setDisplaySetMetadataInvalidated(
displaySetInstanceUID: string,
invalidateData = true
): void {
const displaySet = this.getDisplaySetByUID(displaySetInstanceUID);

if (!displaySet) {
return;
}

// broadcast event to update listeners with the new displaySets
this._broadcastEvent(
EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED,
displaySetInstanceUID
);
this._broadcastEvent(EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED, {
displaySetInstanceUID,
invalidateData,
});
}

public deleteDisplaySet(displaySetInstanceUID) {
Expand Down
14 changes: 14 additions & 0 deletions platform/core/src/types/DisplaySet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { InstanceMetadata } from './StudyMetadata';

export type DisplaySet = {
displaySetInstanceUID: string;
instances: InstanceMetadata[];
StudyInstanceUID: string;
SeriesInstanceUID?: string;
numImages?: number;
};

export type DisplaySetSeriesMetadataInvalidatedEvent = {
displaySetInstanceUID: string;
invalidateData: boolean;
};
11 changes: 2 additions & 9 deletions platform/core/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import * as Extensions from '../extensions/ExtensionManager';
import * as HangingProtocol from './HangingProtocol';
import Services from './Services';
import Hotkey from '../classes/Hotkey';
import { DisplaySet } from '../services/DisplaySetService/DisplaySetService';
import { DataSourceDefinition } from './DataSource';

export * from '../services/CustomizationService/types';
// Separate out some generic types
export * from './AppConfig';
export * from './Consumer';
export * from './Command';
export * from './DisplaySet';
export * from './StudyMetadata';
export * from './PanelModule';
export * from './IPubSub';
Expand All @@ -19,11 +19,4 @@ export * from './Color';
* Export the types used within the various services and managers, but
* not the services/managers themselves, which are exported at the top level.
*/
export {
Extensions,
HangingProtocol,
Services,
Hotkey,
DisplaySet,
DataSourceDefinition,
};
export { Extensions, HangingProtocol, Services, Hotkey, DataSourceDefinition };
7 changes: 7 additions & 0 deletions platform/docs/docs/configuration/dataSources/dicom-web.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ The following properties can be added to the `configuration` property of each da
##### `dicomUploadEnabled`
A boolean indicating if the DICOM upload to the data source is permitted/accepted or not. A value of true provides a link on the OHIF work list page that allows for DICOM files from the local file system to be uploaded to the data source

:::tip
The [OHIF plugin for Orthanc](https://book.orthanc-server.com/plugins/ohif.html) by default utilizes the DICOM JSON data
source and it has been discovered that only those studies uploaded to Orthanc AFTER the plugin has been installed are
available as DICOM JSON. As such, if the OHIF plugin for Orthanc is desired for studies uploaded prior to installing the plugin,
then consider switching to using [DICOMweb instead](https://book.orthanc-server.com/plugins/ohif.html#using-dicomweb).
:::

![toolbarModule-layout](../../assets/img/uploader.gif)

#### `singlepart`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ There are three events that get broadcasted in `DisplaySetService`:
| DISPLAY_SETS_ADDED | Fires a displayset is added to the displaysets cache |
| DISPLAY_SETS_CHANGED | Fires when a displayset is changed |
| DISPLAY_SETS_REMOVED | Fires when a displayset is removed |
| DISPLAY_SET_SERIES_METADATA_INVALIDATED | Fires when a displayset's series metadata has been altered. An object payload for the event is sent with properties: `displaySetInstanceUID` - the UID of the display set affected; `invalidateData` - boolean indicating if data should be invalidated


## API
Expand Down Expand Up @@ -60,3 +61,5 @@ Let's find out about the public API for `DisplaySetService`.
- `deleteDisplaySet`: Deletes the displaySets from the displaySets cache

- `addActiveDisplaySets`: Adds a new display set independently of the make operation.

- `setDisplaySetMetadataInvalidated`: Fires the `DISPLAY_SET_SERIES_METADATA_INVALIDATED` event.
4 changes: 4 additions & 0 deletions platform/ui/src/components/ThumbnailList/ThumbnailList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const ThumbnailList = ({
imageSrc,
messages,
imageAltText,
isHydratedForDerivedDisplaySet,
}) => {
const isActive = activeDisplaySetInstanceUIDs.includes(
displaySetInstanceUID
Expand Down Expand Up @@ -104,6 +105,9 @@ const ThumbnailList = ({
onThumbnailDoubleClick(displaySetInstanceUID)
}
viewportIdentificator={viewportIdentificator}
isHydratedForDerivedDisplaySet={
isHydratedForDerivedDisplaySet
}
/>
);
default:
Expand Down
25 changes: 21 additions & 4 deletions platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const ThumbnailNoImage = ({
messages,
dragData,
isActive,
isHydratedForDerivedDisplaySet,
}) => {
const [collectedProps, drag, dragPreview] = useDrag({
type: 'displayset',
Expand All @@ -31,8 +32,8 @@ const ThumbnailNoImage = ({
return (
<div
className={classnames(
'flex flex-row flex-1 cursor-pointer outline-none border-transparent hover:border-blue-300 focus:border-blue-300 rounded select-none',
isActive ? 'border-2 border-primary-light' : 'border'
'flex flex-row flex-1 cursor-pointer outline-none hover:border-blue-300 focus:border-blue-300 rounded select-none',
isActive ? 'border-2 border-primary-light' : 'border border-transparent'
)}
style={{
padding: isActive ? '11px' : '12px',
Expand All @@ -47,12 +48,27 @@ const ThumbnailNoImage = ({
<div ref={drag}>
<div className="flex flex-col flex-1">
<div className="flex flex-row items-center flex-1 mb-2">
<Icon name="list-bullets" className="w-12 text-secondary-light" />
<Icon
name="list-bullets"
className={classnames(
'w-12',
isHydratedForDerivedDisplaySet
? 'text-primary-light'
: 'text-secondary-light'
)}
/>
<Tooltip
position="bottom"
content={<Typography>{modalityTooltip}</Typography>}
>
<div className="px-3 text-lg text-white rounded-sm bg-primary-main">
<div
className={classnames(
'px-3 text-lg rounded-sm',
isHydratedForDerivedDisplaySet
? 'text-black bg-primary-light'
: 'text-white bg-primary-main'
)}
>
{modality}
</div>
</Tooltip>
Expand Down Expand Up @@ -116,6 +132,7 @@ ThumbnailNoImage.propTypes = {
onDoubleClick: PropTypes.func.isRequired,
messages: PropTypes.object,
isActive: PropTypes.bool.isRequired,
isHydratedForDerivedDisplaySet: PropTypes.bool,
};

export default ThumbnailNoImage;