feat(multimonitor): Add simple multi-monitor support to open another study(#4178)
This commit is contained in:
1 parent
a4a6de07f4
commit
07c628e689
49 files changed
+1476
-367
No files matched your search
@@ -5,17 +5,6 @@ import { StudyItem } from '../StudyItem';
|
||||
import { StudyBrowserSort } from '../StudyBrowserSort';
|
||||
import { StudyBrowserViewOptions } from '../StudyBrowserViewOptions';
|
||||
|
||||
const getTrackedSeries = displaySets => {
|
||||
let trackedSeries = 0;
|
||||
displaySets.forEach(displaySet => {
|
||||
if (displaySet.isTracked) {
|
||||
trackedSeries++;
|
||||
}
|
||||
});
|
||||
|
||||
return trackedSeries;
|
||||
};
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
const StudyBrowser = ({
|
||||
@@ -31,7 +20,8 @@ const StudyBrowser = ({
|
||||
servicesManager,
|
||||
showSettings,
|
||||
viewPresets,
|
||||
onThumbnailContextMenu,
|
||||
ThumbnailMenuItems,
|
||||
StudyMenuItems,
|
||||
}: withAppTypes) => {
|
||||
const getTabContent = () => {
|
||||
const tabData = tabs.find(tab => tab.name === activeTabName);
|
||||
@@ -50,18 +40,17 @@ const StudyBrowser = ({
|
||||
isExpanded={isExpanded}
|
||||
displaySets={displaySets}
|
||||
modalities={modalities}
|
||||
trackedSeries={getTrackedSeries(displaySets)}
|
||||
isActive={isExpanded}
|
||||
onClick={() => {
|
||||
onClickStudy(studyInstanceUid);
|
||||
}}
|
||||
onClick={() => onClickStudy(studyInstanceUid)}
|
||||
onClickThumbnail={onClickThumbnail}
|
||||
onDoubleClickThumbnail={onDoubleClickThumbnail}
|
||||
onClickUntrack={onClickUntrack}
|
||||
activeDisplaySetInstanceUIDs={activeDisplaySetInstanceUIDs}
|
||||
data-cy="thumbnail-list"
|
||||
viewPreset={viewPreset}
|
||||
onThumbnailContextMenu={onThumbnailContextMenu}
|
||||
ThumbnailMenuItems={ThumbnailMenuItems}
|
||||
StudyMenuItems={StudyMenuItems}
|
||||
StudyInstanceUID={studyInstanceUid}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
@@ -142,6 +131,7 @@ StudyBrowser.propTypes = {
|
||||
).isRequired,
|
||||
})
|
||||
),
|
||||
StudyMenuItems: PropTypes.func,
|
||||
};
|
||||
|
||||
export { StudyBrowser };
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
} from '../DropdownMenu/DropdownMenu';
|
||||
|
||||
export function StudyBrowserSort({ servicesManager }: withAppTypes) {
|
||||
// Todo: this should not be here, no servicesManager should be in ui-next, only
|
||||
// customization service
|
||||
const { customizationService, displaySetService } = servicesManager.services;
|
||||
const { values: sortFunctions } = customizationService.get('studyBrowser.sortFunctions');
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ const StudyItem = ({
|
||||
onDoubleClickThumbnail,
|
||||
onClickUntrack,
|
||||
viewPreset = 'thumbnails',
|
||||
onThumbnailContextMenu,
|
||||
ThumbnailMenuItems,
|
||||
StudyMenuItems,
|
||||
StudyInstanceUID,
|
||||
}: withAppTypes) => {
|
||||
return (
|
||||
<Accordion
|
||||
@@ -32,19 +34,24 @@ const StudyItem = ({
|
||||
defaultValue={isActive ? 'study-item' : undefined}
|
||||
>
|
||||
<AccordionItem value="study-item">
|
||||
<AccordionTrigger className={classnames('hover:bg-accent bg-popover rounded')}>
|
||||
<AccordionTrigger className={classnames('hover:bg-accent bg-popover group rounded')}>
|
||||
<div className="flex h-[40px] flex-1 flex-row">
|
||||
<div className="flex w-full flex-row items-center justify-between">
|
||||
<div className="flex w-full flex-row items-center">
|
||||
<div className="flex flex-col items-start text-[13px]">
|
||||
<div className="text-white">{date}</div>
|
||||
<div className="text-muted-foreground h-[18px] max-w-[160px] overflow-hidden truncate whitespace-nowrap">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-muted-foreground mr-2 flex flex-col items-end text-[12px]">
|
||||
<div className="text-muted-foreground ml-auto flex flex-col items-end text-[12px]">
|
||||
<div className="max-w-[150px] overflow-hidden text-ellipsis">{modalities}</div>
|
||||
<div>{numInstances}</div>
|
||||
</div>
|
||||
{StudyMenuItems && (
|
||||
<div className="ml-2 flex items-center">
|
||||
<StudyMenuItems StudyInstanceUID={StudyInstanceUID} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
@@ -61,7 +68,7 @@ const StudyItem = ({
|
||||
onThumbnailDoubleClick={onDoubleClickThumbnail}
|
||||
onClickUntrack={onClickUntrack}
|
||||
viewPreset={viewPreset}
|
||||
onThumbnailContextMenu={onThumbnailContextMenu}
|
||||
ThumbnailMenuItems={ThumbnailMenuItems}
|
||||
/>
|
||||
)}
|
||||
</AccordionContent>
|
||||
@@ -75,7 +82,6 @@ StudyItem.propTypes = {
|
||||
description: PropTypes.string,
|
||||
modalities: PropTypes.string.isRequired,
|
||||
numInstances: PropTypes.number.isRequired,
|
||||
trackedSeries: PropTypes.number,
|
||||
isActive: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
isExpanded: PropTypes.bool,
|
||||
@@ -85,6 +91,8 @@ StudyItem.propTypes = {
|
||||
onDoubleClickThumbnail: PropTypes.func,
|
||||
onClickUntrack: PropTypes.func,
|
||||
viewPreset: PropTypes.string,
|
||||
StudyMenuItems: PropTypes.func,
|
||||
StudyInstanceUID: PropTypes.string,
|
||||
};
|
||||
|
||||
export { StudyItem };
|
||||
@@ -5,13 +5,6 @@ import { useDrag } from 'react-dnd';
|
||||
import { Icons } from '../Icons';
|
||||
import { DisplaySetMessageListTooltip } from '../DisplaySetMessageListTooltip';
|
||||
import { TooltipTrigger, TooltipContent, Tooltip } from '../Tooltip';
|
||||
import { Button } from '../Button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '../DropdownMenu';
|
||||
|
||||
/**
|
||||
* Display a thumbnail for a display set.
|
||||
@@ -34,12 +27,12 @@ const Thumbnail = ({
|
||||
viewPreset = 'thumbnails',
|
||||
modality,
|
||||
isHydratedForDerivedDisplaySet = false,
|
||||
isTracked = false,
|
||||
canReject = false,
|
||||
onReject = () => {},
|
||||
isTracked = false,
|
||||
thumbnailType = 'thumbnail',
|
||||
onClickUntrack = () => {},
|
||||
onThumbnailContextMenu,
|
||||
ThumbnailMenuItems = () => {},
|
||||
}: withAppTypes): React.ReactNode => {
|
||||
// TODO: We should wrap our thumbnail to create a "DraggableThumbnail", as
|
||||
// this will still allow for "drag", even if there is no drop target for the
|
||||
@@ -134,44 +127,11 @@ const Thumbnail = ({
|
||||
</div>
|
||||
{/* bottom right */}
|
||||
<div className="absolute bottom-0 right-0 flex items-center gap-[4px] p-[4px]">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="hidden group-hover:inline-flex data-[state=open]:inline-flex"
|
||||
>
|
||||
<Icons.More />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
hideWhenDetached
|
||||
align="start"
|
||||
>
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
onThumbnailContextMenu('openDICOMTagViewer', {
|
||||
displaySetInstanceUID,
|
||||
});
|
||||
}}
|
||||
className="gap-[6px]"
|
||||
>
|
||||
<Icons.DicomTagBrowser />
|
||||
Tag Browser
|
||||
</DropdownMenuItem>
|
||||
{canReject && (
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
onReject();
|
||||
}}
|
||||
className="gap-[6px]"
|
||||
>
|
||||
<Icons.Trash className="h-5 w-5 text-red-500" />
|
||||
Delete Report
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<ThumbnailMenuItems
|
||||
displaySetInstanceUID={displaySetInstanceUID}
|
||||
canReject={canReject}
|
||||
onReject={onReject}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -243,7 +203,6 @@ const Thumbnail = ({
|
||||
messages={messages}
|
||||
id={`display-set-tooltip-${displaySetInstanceUID}`}
|
||||
/>
|
||||
|
||||
{isTracked && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
@@ -271,41 +230,11 @@ const Thumbnail = ({
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="hidden group-hover:inline-flex data-[state=open]:inline-flex"
|
||||
>
|
||||
<Icons.More />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent hideWhenDetached>
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
onThumbnailContextMenu('openDICOMTagViewer', {
|
||||
displaySetInstanceUID,
|
||||
});
|
||||
}}
|
||||
className="gap-[6px]"
|
||||
>
|
||||
<Icons.DicomTagBrowser />
|
||||
Tag Browser
|
||||
</DropdownMenuItem>
|
||||
{canReject && (
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
onReject();
|
||||
}}
|
||||
className="gap-[6px]"
|
||||
>
|
||||
<Icons.Trash className="h-5 w-5 text-red-500" />
|
||||
Delete Report
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<ThumbnailMenuItems
|
||||
displaySetInstanceUID={displaySetInstanceUID}
|
||||
canReject={canReject}
|
||||
onReject={onReject}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -369,8 +298,6 @@ Thumbnail.propTypes = {
|
||||
viewPreset: PropTypes.string,
|
||||
modality: PropTypes.string,
|
||||
isHydratedForDerivedDisplaySet: PropTypes.bool,
|
||||
canReject: PropTypes.bool,
|
||||
onReject: PropTypes.func,
|
||||
isTracked: PropTypes.bool,
|
||||
onClickUntrack: PropTypes.func,
|
||||
countIcon: PropTypes.string,
|
||||
|
||||
@@ -10,7 +10,7 @@ const ThumbnailList = ({
|
||||
onClickUntrack,
|
||||
activeDisplaySetInstanceUIDs = [],
|
||||
viewPreset,
|
||||
onThumbnailContextMenu,
|
||||
ThumbnailMenuItems,
|
||||
}: withAppTypes) => {
|
||||
return (
|
||||
<div
|
||||
@@ -34,9 +34,9 @@ const ThumbnailList = ({
|
||||
modality,
|
||||
componentType,
|
||||
countIcon,
|
||||
isTracked,
|
||||
canReject,
|
||||
onReject,
|
||||
isTracked,
|
||||
imageSrc,
|
||||
messages,
|
||||
imageAltText,
|
||||
@@ -56,6 +56,8 @@ const ThumbnailList = ({
|
||||
imageAltText={imageAltText}
|
||||
messages={messages}
|
||||
isActive={isActive}
|
||||
canReject={canReject}
|
||||
onReject={onReject}
|
||||
modality={modality}
|
||||
viewPreset={componentType === 'thumbnailNoImage' ? 'list' : viewPreset}
|
||||
thumbnailType={componentType}
|
||||
@@ -65,9 +67,7 @@ const ThumbnailList = ({
|
||||
loadingProgress={loadingProgress}
|
||||
onClickUntrack={() => onClickUntrack(displaySetInstanceUID)}
|
||||
isHydratedForDerivedDisplaySet={isHydratedForDerivedDisplaySet}
|
||||
canReject={canReject}
|
||||
onReject={onReject}
|
||||
onThumbnailContextMenu={onThumbnailContextMenu}
|
||||
ThumbnailMenuItems={ThumbnailMenuItems}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user