Merge branch 'feat/v2-main' of https://github.com/OHIF/Viewers into feat/ui-v2-Dropdown
This commit is contained in:
commit
0d53346d61
73 files changed
+1423
-369
No files matched your search
@@ -34,7 +34,7 @@
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"webpack": "^4.0.0",
|
||||
"dcmjs": "^0.12.4"
|
||||
"dcmjs": "0.14.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6"
|
||||
|
||||
@@ -12,9 +12,16 @@ import getImageId from './utils/getImageId';
|
||||
import * as dcmjs from 'dcmjs';
|
||||
import { retrieveStudyMetadata } from './retrieveStudyMetadata.js';
|
||||
|
||||
const { naturalizeDataset } = dcmjs.data.DicomMetaDictionary;
|
||||
const { DicomMetaDictionary, DicomDict } = dcmjs.data;
|
||||
|
||||
const { naturalizeDataset, denaturalizeDataset } = DicomMetaDictionary;
|
||||
const { urlUtil } = utils;
|
||||
|
||||
const ImplementationClassUID =
|
||||
'2.25.270695996825855179949881587723571202391.2.0.0';
|
||||
const ImplementationVersionName = 'OHIF-VIEWER-2.0.0';
|
||||
const EXPLICIT_VR_LITTLE_ENDIAN = '1.2.840.10008.1.2.1';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} name - Data source name
|
||||
@@ -128,6 +135,32 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
},
|
||||
},
|
||||
},
|
||||
store: {
|
||||
dicom: async dataset => {
|
||||
const meta = {
|
||||
FileMetaInformationVersion:
|
||||
dataset._meta.FileMetaInformationVersion.Value,
|
||||
MediaStorageSOPClassUID: dataset.SOPClassUID,
|
||||
MediaStorageSOPInstanceUID: dataset.SOPInstanceUID,
|
||||
TransferSyntaxUID: EXPLICIT_VR_LITTLE_ENDIAN,
|
||||
ImplementationClassUID,
|
||||
ImplementationVersionName,
|
||||
};
|
||||
|
||||
const denaturalized = denaturalizeDataset(meta);
|
||||
const dicomDict = new DicomDict(denaturalized);
|
||||
|
||||
dicomDict.dict = denaturalizeDataset(dataset);
|
||||
|
||||
const part10Buffer = dicomDict.write();
|
||||
|
||||
const options = {
|
||||
datasets: [part10Buffer],
|
||||
};
|
||||
|
||||
await wadoDicomWebClient.storeInstances(options);
|
||||
},
|
||||
},
|
||||
retrieveSeriesMetadata: async ({ StudyInstanceUID } = {}) => {
|
||||
if (!StudyInstanceUID) {
|
||||
throw new Error(
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* | limit | {number} |
|
||||
* | offset | {number} |
|
||||
*/
|
||||
import { DICOMWeb } from '@ohif/core';
|
||||
import { DICOMWeb, utils } from '@ohif/core';
|
||||
|
||||
const { getString, getName, getModalities } = DICOMWeb;
|
||||
|
||||
@@ -50,7 +50,7 @@ function processResults(qidoStudies) {
|
||||
time: getString(qidoStudy['00080030']), // HHmmss.SSS (24-hour, minutes, seconds, fractional seconds)
|
||||
accession: getString(qidoStudy['00080050']) || '', // short string, probably a number?
|
||||
mrn: getString(qidoStudy['00100020']) || '', // medicalRecordNumber
|
||||
patientName: getName(qidoStudy['00100010']) || '',
|
||||
patientName: utils.formatPN(getName(qidoStudy['00100010'])) || '',
|
||||
instances: Number(getString(qidoStudy['00201208'])) || 0, // number
|
||||
description: getString(qidoStudy['00081030']) || '',
|
||||
modalities:
|
||||
|
||||
@@ -127,7 +127,6 @@ function PanelStudyBrowser({
|
||||
changedDisplaySets,
|
||||
thumbnailImageSrcMap
|
||||
);
|
||||
|
||||
setDisplaySets(mappedDisplaySets);
|
||||
}
|
||||
);
|
||||
@@ -152,11 +151,11 @@ function PanelStudyBrowser({
|
||||
);
|
||||
const updatedExpandedStudyInstanceUIDs = shouldCollapseStudy
|
||||
? // eslint-disable-next-line prettier/prettier
|
||||
[
|
||||
...expandedStudyInstanceUIDs.filter(
|
||||
stdyUid => stdyUid !== StudyInstanceUID
|
||||
),
|
||||
]
|
||||
[
|
||||
...expandedStudyInstanceUIDs.filter(
|
||||
stdyUid => stdyUid !== StudyInstanceUID
|
||||
),
|
||||
]
|
||||
: [...expandedStudyInstanceUIDs, StudyInstanceUID];
|
||||
|
||||
setExpandedStudyInstanceUIDs(updatedExpandedStudyInstanceUIDs);
|
||||
|
||||
@@ -20,7 +20,7 @@ function WrappedPanelStudyBrowser({
|
||||
}) {
|
||||
// TODO: This should be made available a different way; route should have
|
||||
// already determined our datasource
|
||||
const dataSource = extensionManager.getDataSources('dicomweb')[0];
|
||||
const dataSource = extensionManager.getDataSources()[0];
|
||||
const _getStudiesForPatientByStudyInstanceUID = getStudiesForPatientByStudyInstanceUID.bind(
|
||||
null,
|
||||
dataSource
|
||||
|
||||
@@ -5,22 +5,40 @@ import {
|
||||
useViewportGrid,
|
||||
} from '@ohif/ui';
|
||||
|
||||
const DEFAULT_LAYOUT = {
|
||||
type: 'SET_LAYOUT',
|
||||
payload: {
|
||||
numCols: 1,
|
||||
numRows: 1,
|
||||
},
|
||||
};
|
||||
|
||||
function LayoutSelector() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [viewportGridState, dispatch] = useViewportGrid();
|
||||
|
||||
useEffect(() => {
|
||||
function closeOnOutsideClick() {
|
||||
if (isOpen) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
const closeOnOutsideClick = () => {
|
||||
if (isOpen) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('click', closeOnOutsideClick);
|
||||
return () => {
|
||||
window.removeEventListener('click', closeOnOutsideClick);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
/* Reset to default layout when component unmounts */
|
||||
return () => {
|
||||
dispatch(DEFAULT_LAYOUT);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onClickHandler = () => setIsOpen(!isOpen);
|
||||
|
||||
const DropdownContent = isOpen ? OHIFLayoutSelector : null;
|
||||
|
||||
return (
|
||||
@@ -28,9 +46,7 @@ function LayoutSelector() {
|
||||
id="Layout"
|
||||
label="Grid Layout"
|
||||
icon="tool-layout"
|
||||
onClick={() => {
|
||||
setIsOpen(!isOpen);
|
||||
}}
|
||||
onClick={onClickHandler}
|
||||
dropdownContent={
|
||||
DropdownContent !== null && (
|
||||
<DropdownContent
|
||||
|
||||
@@ -2,33 +2,32 @@ import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ToolbarButton } from '@ohif/ui';
|
||||
|
||||
function NestedMenu({ children }) {
|
||||
function NestedMenu({ children, label, icon, isActive }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
function closeNestedMenu() {
|
||||
if (isOpen) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
const toggleNestedMenu = () => setIsOpen(!isOpen);
|
||||
|
||||
const closeNestedMenu = () => {
|
||||
if (isOpen) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('click', closeNestedMenu);
|
||||
return () => {
|
||||
window.removeEventListener('click', closeNestedMenu);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
const dropdownContent = isOpen ? children : undefined;
|
||||
|
||||
return (
|
||||
<ToolbarButton
|
||||
id="More"
|
||||
label="More"
|
||||
icon="tool-more-menu"
|
||||
onClick={() => {
|
||||
setIsOpen(!isOpen);
|
||||
}}
|
||||
dropdownContent={dropdownContent}
|
||||
isActive={isOpen}
|
||||
id="NestedMenu"
|
||||
label={label}
|
||||
icon={icon}
|
||||
onClick={toggleNestedMenu}
|
||||
dropdownContent={isOpen && children}
|
||||
isActive={isActive || isOpen}
|
||||
type="primary"
|
||||
/>
|
||||
);
|
||||
@@ -36,6 +35,13 @@ function NestedMenu({ children }) {
|
||||
|
||||
NestedMenu.propTypes = {
|
||||
children: PropTypes.any.isRequired,
|
||||
icon: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
};
|
||||
|
||||
NestedMenu.defaultProps = {
|
||||
icon: "tool-more-menu",
|
||||
label: "More",
|
||||
};
|
||||
|
||||
export default NestedMenu;
|
||||
@@ -55,7 +55,20 @@ function ViewerLayout({
|
||||
};
|
||||
};
|
||||
|
||||
const defaultTool = { icon: 'tool-more-menu', label: 'More', isActive: false };
|
||||
const [toolbars, setToolbars] = useState({ primary: [], secondary: [] });
|
||||
const [activeTool, setActiveTool] = useState(defaultTool);
|
||||
|
||||
const setActiveToolHandler = (tool, isNested) => {
|
||||
setActiveTool(isNested ? tool : defaultTool);
|
||||
};
|
||||
|
||||
const onPrimaryClickHandler = (evt, btn) => {
|
||||
if (btn.props && btn.props.commands && evt.value && btn.props.commands[evt.value]) {
|
||||
const { commandName, commandOptions } = btn.props.commands[evt.value];
|
||||
commandsManager.runCommand(commandName, commandOptions);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = ToolBarService.subscribe(
|
||||
@@ -63,8 +76,8 @@ function ViewerLayout({
|
||||
() => {
|
||||
console.warn('~~~ TOOL BAR MODIFIED EVENT CAUGHT');
|
||||
const updatedToolbars = {
|
||||
primary: ToolBarService.getButtonSection('primary'),
|
||||
secondary: ToolBarService.getButtonSection('secondary'),
|
||||
primary: ToolBarService.getButtonSection('primary', { onClick: onPrimaryClickHandler, setActiveTool: setActiveToolHandler }),
|
||||
secondary: ToolBarService.getButtonSection('secondary', { setActiveTool: setActiveToolHandler }),
|
||||
};
|
||||
setToolbars(updatedToolbars);
|
||||
}
|
||||
@@ -86,11 +99,10 @@ function ViewerLayout({
|
||||
|
||||
if (!isNested) {
|
||||
const { id, Component, componentProps } = toolDef;
|
||||
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
} else {
|
||||
return (
|
||||
<NestedMenu>
|
||||
<NestedMenu isActive={activeTool.isActive} icon={activeTool.icon} label={activeTool.label}>
|
||||
<div className="flex">
|
||||
{toolDef.map(x => {
|
||||
const { id, Component, componentProps } = x;
|
||||
|
||||
@@ -9,7 +9,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
{
|
||||
name: 'ohif.divider',
|
||||
defaultComponent: ToolbarDivider,
|
||||
clickHandler: () => {},
|
||||
clickHandler: () => { },
|
||||
},
|
||||
{
|
||||
name: 'ohif.action',
|
||||
@@ -30,7 +30,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
optionalConfig: [],
|
||||
requiredProps: [],
|
||||
optionalProps: [],
|
||||
clickHandler: (evt, clickedBtn, btnSectionName) => {
|
||||
clickHandler: (evt, clickedBtn, btnSectionName, metadata, viewerProps) => {
|
||||
const { props } = clickedBtn;
|
||||
const allButtons = toolbarService.getButtons();
|
||||
|
||||
@@ -47,6 +47,10 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
clickedBtn.config.groupName === btn.config.groupName
|
||||
) {
|
||||
btn.props.isActive = false;
|
||||
|
||||
if (viewerProps.setActiveTool) {
|
||||
viewerProps.setActiveTool(props, metadata.isNested);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -63,7 +67,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
|
||||
{
|
||||
name: 'ohif.layoutSelector',
|
||||
defaultComponent: ToolbarLayoutSelector,
|
||||
clickHandler: (evt, clickedBtn, btnSectionName) => {},
|
||||
clickHandler: (evt, clickedBtn, btnSectionName) => { },
|
||||
},
|
||||
{
|
||||
name: 'ohif.toggle',
|
||||
|
||||
Reference in new issue
Block a user