diff --git a/extensions/default/src/ViewerLayout/ResizablePanelsHook.tsx b/extensions/default/src/ViewerLayout/ResizablePanelsHook.tsx index 9b7c37796..10fa5ddb8 100644 --- a/extensions/default/src/ViewerLayout/ResizablePanelsHook.tsx +++ b/extensions/default/src/ViewerLayout/ResizablePanelsHook.tsx @@ -1,22 +1,6 @@ import { useState, useCallback, useLayoutEffect, useRef } from 'react'; import { getPanelElement, getPanelGroupElement } from 'react-resizable-panels'; - -// Id needed to grab the panel group for converting pixels to percentages -const viewerLayoutResizablePanelGroupId = 'viewerLayoutResizablePanelGroup'; -const viewerLayoutResizableLeftPanelId = 'viewerLayoutResizableLeftPanel'; -const viewerLayoutResizableRightPanelId = 'viewerLayoutResizableRightPanel'; - -const sidePanelExpandedDefaultWidth = 280; -const sidePanelExpandedInsideBorderSize = 4; -const sidePanelExpandedDefaultOffsetWidth = - sidePanelExpandedDefaultWidth + sidePanelExpandedInsideBorderSize; -const sidePanelCollapsedInsideBorderSize = 4; -const sidePanelCollapsedOutsideBorderSize = 8; -const sidePanelCollapsedWidth = 25; -const sidePanelCollapsedOffsetWidth = - sidePanelCollapsedWidth + - sidePanelCollapsedInsideBorderSize + - sidePanelCollapsedOutsideBorderSize; +import { panelGroupDefinition } from './constants/panels'; /** * Set the minimum and maximum css style width attributes for the given element. @@ -43,15 +27,15 @@ const useResizablePanels = ( setRightPanelClosed ) => { const [leftPanelExpandedWidth, setLeftPanelExpandedWidth] = useState( - sidePanelExpandedDefaultWidth + panelGroupDefinition.left.initialExpandedWidth ); const [rightPanelExpandedWidth, setRightPanelExpandedWidth] = useState( - sidePanelExpandedDefaultWidth + panelGroupDefinition.right.initialExpandedWidth ); - - // Percentage sizes. - const [resizablePanelCollapsedSize, setResizablePanelCollapsedSize] = useState(0); - const [resizablePanelDefaultSize, setResizablePanelDefaultSize] = useState(0); + const [leftResizablePanelMinimumSize, setLeftResizablePanelMinimumSize] = useState(0); + const [rightResizablePanelMinimumSize, setRightResizablePanelMinimumSize] = useState(0); + const [leftResizeablePanelCollapsedSize, setLeftResizePanelCollapsedSize] = useState(0); + const [rightResizePanelCollapsedSize, setRightResizePanelCollapsedSize] = useState(0); const resizablePanelGroupElemRef = useRef(null); const resizableLeftPanelElemRef = useRef(null); @@ -65,30 +49,33 @@ const useResizablePanels = ( // converting between percentages and pixels in various callbacks. // - Expand those panels that are initially expanded. useLayoutEffect(() => { - const panelGroupElem = getPanelGroupElement(viewerLayoutResizablePanelGroupId); + const panelGroupElem = getPanelGroupElement(panelGroupDefinition.groupId); resizablePanelGroupElemRef.current = panelGroupElem; const { width: panelGroupWidth } = panelGroupElem.getBoundingClientRect(); - const leftPanelElem = getPanelElement(viewerLayoutResizableLeftPanelId); + const leftPanelElem = getPanelElement(panelGroupDefinition.left.panelId); resizableLeftPanelElemRef.current = leftPanelElem; - const rightPanelElem = getPanelElement(viewerLayoutResizableRightPanelId); + const rightPanelElem = getPanelElement(panelGroupDefinition.right.panelId); resizableRightPanelElemRef.current = rightPanelElem; - const resizablePanelExpandedSize = - (sidePanelExpandedDefaultOffsetWidth / panelGroupWidth) * 100; - // Since both resizable panels are collapsed by default (i.e. their default size is zero), // on the very first render check if either/both side panels should be expanded. + // we use the initialExpandedOffsetWidth on the first render incase the panel has min width but we want the initial state to be larger than that + if (!leftPanelClosed) { - resizableLeftPanelAPIRef?.current?.expand(resizablePanelExpandedSize); - setMinMaxWidth(leftPanelElem, sidePanelExpandedDefaultOffsetWidth); + const leftResizablePanelExpandedSize = + (panelGroupDefinition.left.initialExpandedOffsetWidth / panelGroupWidth) * 100; + resizableLeftPanelAPIRef?.current?.expand(leftResizablePanelExpandedSize); + setMinMaxWidth(leftPanelElem, panelGroupDefinition.left.initialExpandedOffsetWidth); } if (!rightPanelClosed) { - resizableRightPanelAPIRef?.current?.expand(resizablePanelExpandedSize); - setMinMaxWidth(rightPanelElem, sidePanelExpandedDefaultOffsetWidth); + const rightResizablePanelExpandedSize = + (panelGroupDefinition.right.initialExpandedOffsetWidth / panelGroupWidth) * 100; + resizableRightPanelAPIRef?.current?.expand(rightResizablePanelExpandedSize); + setMinMaxWidth(rightPanelElem, panelGroupDefinition.right.initialExpandedOffsetWidth); } }, []); // no dependencies because this useLayoutEffect is only needed on the very first render @@ -114,13 +101,17 @@ const useResizablePanels = ( // for a panel. if (!resizableLeftPanelAPIRef.current.isCollapsed()) { const leftSize = - ((leftPanelExpandedWidth + sidePanelExpandedInsideBorderSize) / panelGroupWidth) * 100; + ((leftPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize) / + panelGroupWidth) * + 100; resizableLeftPanelAPIRef.current.resize(leftSize); } if (!resizableRightPanelAPIRef.current.isCollapsed()) { const rightSize = - ((rightPanelExpandedWidth + sidePanelExpandedInsideBorderSize) / panelGroupWidth) * 100; + ((rightPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize) / + panelGroupWidth) * + 100; resizableRightPanelAPIRef.current.resize(rightSize); } @@ -128,11 +119,20 @@ const useResizablePanels = ( // component is resized. This typically occurs when the browser window resizes. const observer = new ResizeObserver(() => { const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect(); - const defaultSize = (sidePanelExpandedDefaultOffsetWidth / panelGroupWidth) * 100; + const minimumLeftSize = + (panelGroupDefinition.left.minimumExpandedOffsetWidth / panelGroupWidth) * 100; + const minimumRightSize = + (panelGroupDefinition.right.minimumExpandedOffsetWidth / panelGroupWidth) * 100; // Set the new default and collapsed resizable panel sizes. - setResizablePanelDefaultSize(Math.min(50, defaultSize)); - setResizablePanelCollapsedSize((sidePanelCollapsedOffsetWidth / panelGroupWidth) * 100); + setLeftResizablePanelMinimumSize(Math.min(50, minimumLeftSize)); + setRightResizablePanelMinimumSize(Math.min(50, minimumRightSize)); + setLeftResizePanelCollapsedSize( + (panelGroupDefinition.left.collapsedOffsetWidth / panelGroupWidth) * 100 + ); + setRightResizePanelCollapsedSize( + (panelGroupDefinition.right.collapsedOffsetWidth / panelGroupWidth) * 100 + ); if ( resizableLeftPanelAPIRef.current.isCollapsed() && @@ -146,12 +146,12 @@ const useResizablePanels = ( // Determine the current widths of the two side panels. let leftPanelOffsetWidth = resizableLeftPanelAPIRef.current.isCollapsed() - ? sidePanelCollapsedOffsetWidth - : leftPanelExpandedWidth + sidePanelExpandedInsideBorderSize; + ? panelGroupDefinition.left.collapsedOffsetWidth + : leftPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize; let rightPanelOffsetWidth = resizableRightPanelAPIRef.current.isCollapsed() - ? sidePanelCollapsedOffsetWidth - : rightPanelExpandedWidth + sidePanelExpandedInsideBorderSize; + ? panelGroupDefinition.right.collapsedOffsetWidth + : rightPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize; if ( !resizableLeftPanelAPIRef.current.isCollapsed() && @@ -162,9 +162,11 @@ const useResizablePanels = ( // Reduce the left panel width so that both panels might fit. leftPanelOffsetWidth = Math.max( panelGroupWidth - rightPanelOffsetWidth, - sidePanelExpandedDefaultOffsetWidth + panelGroupDefinition.left.minimumExpandedOffsetWidth + ); + setLeftPanelExpandedWidth( + leftPanelOffsetWidth - panelGroupDefinition.shared.expandedInsideBorderSize ); - setLeftPanelExpandedWidth(leftPanelOffsetWidth - sidePanelExpandedInsideBorderSize); setMinMaxWidth(resizableLeftPanelElemRef.current, leftPanelOffsetWidth); } @@ -177,9 +179,11 @@ const useResizablePanels = ( // Reduce the right panel width so that both panels might fit. rightPanelOffsetWidth = Math.max( panelGroupWidth - leftPanelOffsetWidth, - sidePanelExpandedDefaultOffsetWidth + panelGroupDefinition.right.minimumExpandedOffsetWidth + ); + setRightPanelExpandedWidth( + rightPanelOffsetWidth - panelGroupDefinition.shared.expandedInsideBorderSize ); - setRightPanelExpandedWidth(rightPanelOffsetWidth - sidePanelExpandedInsideBorderSize); setMinMaxWidth(resizableRightPanelElemRef.current, rightPanelOffsetWidth); } }); @@ -189,7 +193,12 @@ const useResizablePanels = ( return () => { observer.disconnect(); }; - }, [leftPanelExpandedWidth, resizablePanelDefaultSize, rightPanelExpandedWidth]); + }, [ + leftPanelExpandedWidth, + rightPanelExpandedWidth, + leftResizablePanelMinimumSize, + rightResizablePanelMinimumSize, + ]); /** * Handles dragging of either side panel resize handle. @@ -207,14 +216,14 @@ const useResizablePanels = ( if (resizableLeftPanelAPIRef?.current?.isExpanded()) { setMinMaxWidth( resizableLeftPanelElemRef.current, - leftPanelExpandedWidth + sidePanelExpandedInsideBorderSize + leftPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize ); } if (resizableRightPanelAPIRef?.current?.isExpanded()) { setMinMaxWidth( resizableRightPanelElemRef.current, - rightPanelExpandedWidth + sidePanelExpandedInsideBorderSize + rightPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize ); } } @@ -229,15 +238,12 @@ const useResizablePanels = ( }, [setLeftPanelClosed]); const onLeftPanelOpen = useCallback(() => { - resizableLeftPanelAPIRef?.current?.expand(); - if (!isResizableHandleDraggingRef.current) { - setMinMaxWidth( - resizableLeftPanelElemRef.current, - leftPanelExpandedWidth + sidePanelExpandedInsideBorderSize - ); - } + const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect(); + resizableLeftPanelAPIRef?.current?.expand( + (panelGroupDefinition.left.initialExpandedOffsetWidth / panelGroupWidth) * 100 + ); setLeftPanelClosed(false); - }, [leftPanelExpandedWidth, setLeftPanelClosed]); + }, [setLeftPanelClosed]); const onLeftPanelResize = useCallback(size => { if (resizableLeftPanelAPIRef.current.isCollapsed()) { @@ -245,7 +251,10 @@ const useResizablePanels = ( } const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect(); - setLeftPanelExpandedWidth((size / 100) * panelGroupWidth - sidePanelExpandedInsideBorderSize); + const newExpandedWidth = + (size / 100) * panelGroupWidth - panelGroupDefinition.shared.expandedInsideBorderSize; + + setLeftPanelExpandedWidth(newExpandedWidth); }, []); const onRightPanelClose = useCallback(() => { @@ -255,68 +264,69 @@ const useResizablePanels = ( }, [setRightPanelClosed]); const onRightPanelOpen = useCallback(() => { - resizableRightPanelAPIRef?.current?.expand(); - if (!isResizableHandleDraggingRef.current) { - setMinMaxWidth( - resizableRightPanelElemRef.current, - rightPanelExpandedWidth + sidePanelExpandedInsideBorderSize - ); - } + const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect(); + resizableRightPanelAPIRef?.current?.expand( + (panelGroupDefinition.right.initialExpandedOffsetWidth / panelGroupWidth) * 100 + ); setRightPanelClosed(false); - }, [rightPanelExpandedWidth, setRightPanelClosed]); + }, [setRightPanelClosed]); const onRightPanelResize = useCallback(size => { if (resizableRightPanelAPIRef?.current?.isCollapsed()) { return; } + const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect(); - setRightPanelExpandedWidth((size / 100) * panelGroupWidth - sidePanelExpandedInsideBorderSize); + const newExpandedWidth = + (size / 100) * panelGroupWidth - panelGroupDefinition.shared.expandedInsideBorderSize; + + setRightPanelExpandedWidth(newExpandedWidth); }, []); return [ { expandedWidth: leftPanelExpandedWidth, - collapsedWidth: sidePanelCollapsedWidth, - collapsedInsideBorderSize: sidePanelCollapsedInsideBorderSize, - collapsedOutsideBorderSize: sidePanelCollapsedOutsideBorderSize, - expandedInsideBorderSize: sidePanelExpandedInsideBorderSize, + collapsedWidth: panelGroupDefinition.shared.collapsedWidth, + collapsedInsideBorderSize: panelGroupDefinition.shared.collapsedInsideBorderSize, + collapsedOutsideBorderSize: panelGroupDefinition.shared.collapsedOutsideBorderSize, + expandedInsideBorderSize: panelGroupDefinition.shared.expandedInsideBorderSize, onClose: onLeftPanelClose, onOpen: onLeftPanelOpen, }, { expandedWidth: rightPanelExpandedWidth, - collapsedWidth: sidePanelCollapsedWidth, - collapsedInsideBorderSize: sidePanelCollapsedInsideBorderSize, - collapsedOutsideBorderSize: sidePanelCollapsedOutsideBorderSize, - expandedInsideBorderSize: sidePanelExpandedInsideBorderSize, + collapsedWidth: panelGroupDefinition.shared.collapsedWidth, + collapsedInsideBorderSize: panelGroupDefinition.shared.collapsedInsideBorderSize, + collapsedOutsideBorderSize: panelGroupDefinition.shared.collapsedOutsideBorderSize, + expandedInsideBorderSize: panelGroupDefinition.shared.expandedInsideBorderSize, onClose: onRightPanelClose, onOpen: onRightPanelOpen, }, - { direction: 'horizontal', id: viewerLayoutResizablePanelGroupId }, + { direction: 'horizontal', id: panelGroupDefinition.groupId }, { - defaultSize: resizablePanelDefaultSize, - minSize: resizablePanelDefaultSize, + defaultSize: leftResizablePanelMinimumSize, + minSize: leftResizablePanelMinimumSize, onResize: onLeftPanelResize, collapsible: true, - collapsedSize: resizablePanelCollapsedSize, + collapsedSize: leftResizeablePanelCollapsedSize, onCollapse: () => setLeftPanelClosed(true), onExpand: () => setLeftPanelClosed(false), ref: resizableLeftPanelAPIRef, order: 0, - id: viewerLayoutResizableLeftPanelId, + id: panelGroupDefinition.left.panelId, }, { order: 1, id: 'viewerLayoutResizableViewportGridPanel' }, { - defaultSize: resizablePanelDefaultSize, - minSize: resizablePanelDefaultSize, + defaultSize: rightResizablePanelMinimumSize, + minSize: rightResizablePanelMinimumSize, onResize: onRightPanelResize, collapsible: true, - collapsedSize: resizablePanelCollapsedSize, + collapsedSize: rightResizePanelCollapsedSize, onCollapse: () => setRightPanelClosed(true), onExpand: () => setRightPanelClosed(false), ref: resizableRightPanelAPIRef, order: 2, - id: viewerLayoutResizableRightPanelId, + id: panelGroupDefinition.right.panelId, }, onHandleDragging, ]; diff --git a/extensions/default/src/ViewerLayout/constants/panels.ts b/extensions/default/src/ViewerLayout/constants/panels.ts new file mode 100644 index 000000000..f85af3ed6 --- /dev/null +++ b/extensions/default/src/ViewerLayout/constants/panels.ts @@ -0,0 +1,38 @@ +const expandedInsideBorderSize = 4; +const collapsedInsideBorderSize = 4; +const collapsedOutsideBorderSize = 8; +const collapsedWidth = 25; + +const rightPanelInitialExpandedWidth = 280; +const leftPanelInitialExpandedWidth = 282; + +const panelGroupDefinition = { + groupId: 'viewerLayoutResizablePanelGroup', + shared: { + expandedInsideBorderSize, + collapsedInsideBorderSize, + collapsedOutsideBorderSize, + collapsedWidth, + }, + left: { + // id + panelId: 'viewerLayoutResizableLeftPanel', + // expanded width + initialExpandedWidth: leftPanelInitialExpandedWidth, + // expanded width + expanded inside border + minimumExpandedOffsetWidth: 145 + expandedInsideBorderSize, + // initial expanded width + initialExpandedOffsetWidth: leftPanelInitialExpandedWidth + expandedInsideBorderSize, + // collapsed width + collapsed inside border + collapsed outside border + collapsedOffsetWidth: collapsedWidth + collapsedInsideBorderSize + collapsedOutsideBorderSize, + }, + right: { + panelId: 'viewerLayoutResizableRightPanel', + initialExpandedWidth: rightPanelInitialExpandedWidth, + minimumExpandedOffsetWidth: rightPanelInitialExpandedWidth + expandedInsideBorderSize, + initialExpandedOffsetWidth: rightPanelInitialExpandedWidth + expandedInsideBorderSize, + collapsedOffsetWidth: collapsedWidth + collapsedInsideBorderSize + collapsedOutsideBorderSize, + }, +}; + +export { panelGroupDefinition }; diff --git a/modes/basic-dev-mode/src/index.ts b/modes/basic-dev-mode/src/index.ts index 47cdb6fd9..661a62ad2 100644 --- a/modes/basic-dev-mode/src/index.ts +++ b/modes/basic-dev-mode/src/index.ts @@ -141,7 +141,9 @@ function modeFactory({ modeConfiguration }) { props: { // TODO: Should be optional, or required to pass empty array for slots? leftPanels: [ohif.thumbnailList], + leftPanelResizable: true, rightPanels: [ohif.measurements], + rightPanelResizable: true, viewports: [ { namespace: cs3d.viewport, diff --git a/modes/basic-test-mode/src/index.ts b/modes/basic-test-mode/src/index.ts index 41d9d6341..b37a0bd3b 100644 --- a/modes/basic-test-mode/src/index.ts +++ b/modes/basic-test-mode/src/index.ts @@ -150,8 +150,10 @@ function modeFactory() { // leftPanels: [ohif.thumbnailList], // rightPanels: [dicomSeg.panel, ohif.measurements], leftPanels: [tracked.thumbnailList], + leftPanelResizable: true, // Can use cornerstone.measurements for all measurements rightPanels: [cornerstone.panel, tracked.measurements, cornerstone.measurements], + rightPanelResizable: true, // rightPanelClosed: true, // optional prop to start with collapse panels viewports: [ { diff --git a/modes/microscopy/src/index.tsx b/modes/microscopy/src/index.tsx index 7435dea96..3ca7e4b65 100644 --- a/modes/microscopy/src/index.tsx +++ b/modes/microscopy/src/index.tsx @@ -87,9 +87,11 @@ function modeFactory({ modeConfiguration }) { id: ohif.layout, props: { leftPanels: [ohif.leftPanel], + leftPanelResizable: true, leftPanelClosed: true, // we have problem with rendering thumbnails for microscopy images rightPanelClosed: true, // we do not have the save microscopy measurements yet rightPanels: ['@ohif/extension-dicom-microscopy.panelModule.measure'], + rightPanelResizable: true, viewports: [ { namespace: '@ohif/extension-dicom-microscopy.viewportModule.microscopy-dicom', diff --git a/modes/preclinical-4d/src/index.tsx b/modes/preclinical-4d/src/index.tsx index 21fc1baed..a7ad7a7ae 100644 --- a/modes/preclinical-4d/src/index.tsx +++ b/modes/preclinical-4d/src/index.tsx @@ -158,7 +158,9 @@ function modeFactory({ modeConfiguration }) { id: ohif.layout, props: { leftPanels: [[dynamicVolume.leftPanel, cornerstone.activeViewportWindowLevel]], + leftPanelResizable: true, rightPanels: [], + rightPanelResizable: true, rightPanelClosed: true, viewports: [ { diff --git a/modes/segmentation/src/index.tsx b/modes/segmentation/src/index.tsx index 34e978618..7c51c194c 100644 --- a/modes/segmentation/src/index.tsx +++ b/modes/segmentation/src/index.tsx @@ -132,7 +132,9 @@ function modeFactory({ modeConfiguration }) { id: ohif.layout, props: { leftPanels: [ohif.leftPanel], + leftPanelResizable: true, rightPanels: [cornerstone.panelTool], + rightPanelResizable: true, // leftPanelClosed: true, viewports: [ { diff --git a/modes/tmtv/src/index.ts b/modes/tmtv/src/index.ts index 9c1ba1702..e1dbfffcb 100644 --- a/modes/tmtv/src/index.ts +++ b/modes/tmtv/src/index.ts @@ -215,8 +215,10 @@ function modeFactory({ modeConfiguration }) { id: ohif.layout, props: { leftPanels: [ohif.thumbnailList], + leftPanelResizable: true, leftPanelClosed: true, rightPanels: [tmtv.tmtv, tmtv.petSUV], + rightPanelResizable: true, viewports: [ { namespace: cs3d.viewport, diff --git a/platform/app/cypress/integration/OHIFVideoDisplay.spec.js b/platform/app/cypress/integration/OHIFVideoDisplay.spec.js index ff877034a..704db2ed4 100644 --- a/platform/app/cypress/integration/OHIFVideoDisplay.spec.js +++ b/platform/app/cypress/integration/OHIFVideoDisplay.spec.js @@ -1,5 +1,6 @@ describe('OHIF Video Display', function () { beforeEach(function () { + Cypress.on('uncaught:exception', () => false); cy.openStudyInViewer('2.25.96975534054447904995905761963464388233'); }); diff --git a/platform/ui-next/src/components/StudyBrowser/StudyBrowser.tsx b/platform/ui-next/src/components/StudyBrowser/StudyBrowser.tsx index 33e68f680..41de81eca 100644 --- a/platform/ui-next/src/components/StudyBrowser/StudyBrowser.tsx +++ b/platform/ui-next/src/components/StudyBrowser/StudyBrowser.tsx @@ -63,7 +63,7 @@ const StudyBrowser = ({ className="ohif-scrollbar invisible-scrollbar bg-bkg-low flex flex-1 flex-col gap-[4px] overflow-auto" data-cy={'studyBrowser-panel'} > -
+
{showSettings && (
<> diff --git a/platform/ui-next/src/components/StudyBrowserSort/StudyBrowserSort.tsx b/platform/ui-next/src/components/StudyBrowserSort/StudyBrowserSort.tsx index 4dcbb9c2e..862ef9d6f 100644 --- a/platform/ui-next/src/components/StudyBrowserSort/StudyBrowserSort.tsx +++ b/platform/ui-next/src/components/StudyBrowserSort/StudyBrowserSort.tsx @@ -6,6 +6,7 @@ import { DropdownMenuContent, DropdownMenuItem, } from '../DropdownMenu/DropdownMenu'; +import { Tooltip, TooltipContent, TooltipTrigger } from '../Tooltip'; export function StudyBrowserSort({ servicesManager }: withAppTypes) { // Todo: this should not be here, no servicesManager should be in ui-next, only @@ -50,11 +51,16 @@ export function StudyBrowserSort({ servicesManager }: withAppTypes) { }, [displaySetService, selectedSort, sortDirection]); return ( -
+
- - {selectedSort.label} - + + + + {selectedSort.label} + + + {selectedSort.label} + {sortFunctions.map(sort => ( - + + + + + Sort direction +
); } diff --git a/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx b/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx index 3e7a622ff..738834dd2 100644 --- a/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx +++ b/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx @@ -5,6 +5,7 @@ import { DropdownMenuContent, DropdownMenuItem, } from '../DropdownMenu/DropdownMenu'; +import { Tooltip, TooltipContent, TooltipTrigger } from '../Tooltip'; export function StudyBrowserViewOptions({ tabs, onSelectTab, activeTabName }: withAppTypes) { const handleTabChange = (tabName: string) => { @@ -15,9 +16,14 @@ export function StudyBrowserViewOptions({ tabs, onSelectTab, activeTabName }: wi return ( - - {activeTab?.label} - + + + + {activeTab?.label} + + + {activeTab?.label} + {tabs.map(tab => { const { name, label, studies } = tab; diff --git a/platform/ui-next/src/components/StudyItem/StudyItem.tsx b/platform/ui-next/src/components/StudyItem/StudyItem.tsx index 4c9dee922..20c748be3 100644 --- a/platform/ui-next/src/components/StudyItem/StudyItem.tsx +++ b/platform/ui-next/src/components/StudyItem/StudyItem.tsx @@ -4,6 +4,7 @@ import classnames from 'classnames'; import { ThumbnailList } from '../ThumbnailList'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '../Accordion'; +import { Tooltip, TooltipContent, TooltipTrigger } from '../Tooltip'; const StudyItem = ({ date, @@ -34,16 +35,28 @@ const StudyItem = ({ defaultValue={isActive ? 'study-item' : undefined} > - -
-
-
-
{date}
-
- {description} -
+ +
+
+
+ + {date} + +
+ {date} +
+
+
+ + {description} + +
+ {description} +
+
+
-
+
{modalities}
{numInstances}
diff --git a/platform/ui-next/src/components/Thumbnail/Thumbnail.tsx b/platform/ui-next/src/components/Thumbnail/Thumbnail.tsx index 40134a3a5..5ccb15d81 100644 --- a/platform/ui-next/src/components/Thumbnail/Thumbnail.tsx +++ b/platform/ui-next/src/components/Thumbnail/Thumbnail.tsx @@ -20,17 +20,17 @@ const Thumbnail = ({ loadingProgress, countIcon, messages, - dragData = {}, isActive, onClick, onDoubleClick, - viewPreset = 'thumbnails', + thumbnailType, modality, + viewPreset = 'thumbnails', isHydratedForDerivedDisplaySet = false, isTracked = false, canReject = false, + dragData = {}, onReject = () => {}, - thumbnailType = 'thumbnail', onClickUntrack = () => {}, ThumbnailMenuItems = () => {}, }: withAppTypes): React.ReactNode => { @@ -135,10 +135,15 @@ const Thumbnail = ({
-
-
- {description} -
+
+ + {description} + +
+ {description} +
+
+
S:{seriesNumber}
@@ -165,21 +170,25 @@ const Thumbnail = ({ isActive && 'bg-popover' )} > -
+
-
+
{modality}
- -
- {description} -
+ + {description} + +
+ {description} +
+
+
@@ -246,7 +255,7 @@ const Thumbnail = ({ className, 'bg-muted hover:bg-primary/30 group flex cursor-pointer select-none flex-col rounded outline-none', viewPreset === 'thumbnails' && 'h-[170px] w-[135px]', - viewPreset === 'list' && 'col-span-2 h-[40px] w-[275px]' + viewPreset === 'list' && 'h-[40px] w-full' )} id={`thumbnail-${displaySetInstanceUID}`} data-cy={ diff --git a/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx b/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx index 0b2241d08..b1a088bac 100644 --- a/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx +++ b/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx @@ -11,68 +11,73 @@ const ThumbnailList = ({ activeDisplaySetInstanceUIDs = [], viewPreset, ThumbnailMenuItems, -}: withAppTypes) => { +}) => { + // Filter thumbnails into list items and thumbnail items + const listItems = thumbnails?.filter( + ({ componentType }) => componentType === 'thumbnailNoImage' || viewPreset === 'list' + ); + + const thumbnailItems = thumbnails?.filter( + ({ componentType }) => componentType !== 'thumbnailNoImage' && viewPreset === 'thumbnails' + ); + return ( -
-
- {thumbnails.map( - ({ - displaySetInstanceUID, - description, - dragData, - seriesNumber, - numInstances, - loadingProgress, - modality, - componentType, - countIcon, - canReject, - onReject, - isTracked, - imageSrc, - messages, - imageAltText, - isHydratedForDerivedDisplaySet, - }) => { +
+ {/* Thumbnail Items */} + {thumbnailItems.length > 0 && ( +
+ {thumbnailItems.map(item => { + const { displaySetInstanceUID, componentType, numInstances, ...rest } = item; + const isActive = activeDisplaySetInstanceUIDs.includes(displaySetInstanceUID); return ( onThumbnailClick(displaySetInstanceUID)} - onDoubleClick={() => onThumbnailDoubleClick(displaySetInstanceUID)} - isTracked={isTracked} - loadingProgress={loadingProgress} - onClickUntrack={() => onClickUntrack(displaySetInstanceUID)} - isHydratedForDerivedDisplaySet={isHydratedForDerivedDisplaySet} + viewPreset="thumbnails" + onClick={onThumbnailClick.bind(null, displaySetInstanceUID)} + onDoubleClick={onThumbnailDoubleClick.bind(null, displaySetInstanceUID)} + onClickUntrack={onClickUntrack.bind(null, displaySetInstanceUID)} ThumbnailMenuItems={ThumbnailMenuItems} /> ); - } - )} -
+ })} +
+ )} + {/* List Items */} + {listItems.length > 0 && ( +
+ {listItems.map(item => { + const { displaySetInstanceUID, componentType, numInstances, ...rest } = item; + const isActive = activeDisplaySetInstanceUIDs.includes(displaySetInstanceUID); + return ( + + ); + })} +
+ )}
); }; @@ -107,6 +112,7 @@ ThumbnailList.propTypes = { onThumbnailDoubleClick: PropTypes.func.isRequired, onClickUntrack: PropTypes.func.isRequired, viewPreset: PropTypes.string, + ThumbnailMenuItems: PropTypes.any, }; export { ThumbnailList };