diff --git a/.webpack/webpack.base.js b/.webpack/webpack.base.js index d90236144..26cc23d2c 100644 --- a/.webpack/webpack.base.js +++ b/.webpack/webpack.base.js @@ -81,8 +81,12 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => { 'process.env.BUILD_NUM': JSON.stringify(BUILD_NUM), /* i18n */ 'process.env.USE_LOCIZE': JSON.stringify(process.env.USE_LOCIZE || ''), - 'process.env.LOCIZE_PROJECTID': JSON.stringify(process.env.LOCIZE_PROJECTID || ''), - 'process.env.LOCIZE_API_KEY': JSON.stringify(process.env.LOCIZE_API_KEY || ''), + 'process.env.LOCIZE_PROJECTID': JSON.stringify( + process.env.LOCIZE_PROJECTID || '' + ), + 'process.env.LOCIZE_API_KEY': JSON.stringify( + process.env.LOCIZE_API_KEY || '' + ), }), ], // Fix: https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-285598881 diff --git a/extensions/cornerstone/src/OHIFCornerstoneViewport.js b/extensions/cornerstone/src/OHIFCornerstoneViewport.js index d16916695..54bf5022e 100644 --- a/extensions/cornerstone/src/OHIFCornerstoneViewport.js +++ b/extensions/cornerstone/src/OHIFCornerstoneViewport.js @@ -180,7 +180,7 @@ class OHIFCornerstoneViewport extends Component { if ( displaySet.displaySetInstanceUID !== - prevDisplaySet.displaySetInstanceUID || + prevDisplaySet.displaySetInstanceUID || displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID || displaySet.frameIndex !== prevDisplaySet.frameIndex ) { @@ -216,18 +216,21 @@ class OHIFCornerstoneViewport extends Component { }); } - const debouncedNewImageHandler = debounce(({ currentImageIdIndex, sopInstanceUid }) => { - const { displaySet } = this.props.viewportData; - const { StudyInstanceUID } = displaySet; - if (currentImageIdIndex > 0) { - this.props.onNewImage({ - StudyInstanceUID, - SOPInstanceUID: sopInstanceUid, - frameIndex: currentImageIdIndex, - activeViewportIndex: viewportIndex, - }); - } - }, 700); + const debouncedNewImageHandler = debounce( + ({ currentImageIdIndex, sopInstanceUid }) => { + const { displaySet } = this.props.viewportData; + const { StudyInstanceUID } = displaySet; + if (currentImageIdIndex > 0) { + this.props.onNewImage({ + StudyInstanceUID, + SOPInstanceUID: sopInstanceUid, + frameIndex: currentImageIdIndex, + activeViewportIndex: viewportIndex, + }); + } + }, + 700 + ); return ( <> diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.test.js b/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.test.js index 70d0d7e66..067782d0e 100644 --- a/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.test.js +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.test.js @@ -36,7 +36,10 @@ describe('measurementServiceMappings.js', () => { }; mappings = measurementServiceMappingsFactory(measurementServiceMock); handles = { start: { x: 1, y: 2 }, end: { x: 1, y: 2 } }; - points = [{ x: 1, y: 2 }, { x: 1, y: 2 }]; + points = [ + { x: 1, y: 2 }, + { x: 1, y: 2 }, + ]; csToolsAnnotation = { toolName: definition, measurementData: { diff --git a/extensions/dicom-p10-downloader/src/commandsModule.js b/extensions/dicom-p10-downloader/src/commandsModule.js index f9aa65df3..5c37024b1 100644 --- a/extensions/dicom-p10-downloader/src/commandsModule.js +++ b/extensions/dicom-p10-downloader/src/commandsModule.js @@ -8,9 +8,7 @@ import { import _downloadAndZip from './downloadAndZip'; const { - utils: { - Queue, - }, + utils: { Queue }, } = OHIF; export function getCommands(context) { diff --git a/extensions/dicom-pdf/src/DicomPDFViewport.js b/extensions/dicom-pdf/src/DicomPDFViewport.js index 8df900a66..5387984aa 100644 --- a/extensions/dicom-pdf/src/DicomPDFViewport.js +++ b/extensions/dicom-pdf/src/DicomPDFViewport.js @@ -52,7 +52,10 @@ class DicomPDFViewport extends Component { if (!this.props.useNative) { const pdf = await PDFJS.getDocument(fileURL).promise; - this.setState(state => ({ ...state, pdf }), () => this.updatePDFCanvas()); + this.setState( + state => ({ ...state, pdf }), + () => this.updatePDFCanvas() + ); } } diff --git a/extensions/dicom-rt/src/OHIFDicomRTStructSopClassHandler.js b/extensions/dicom-rt/src/OHIFDicomRTStructSopClassHandler.js index d0a67d113..794f4ef47 100644 --- a/extensions/dicom-rt/src/OHIFDicomRTStructSopClassHandler.js +++ b/extensions/dicom-rt/src/OHIFDicomRTStructSopClassHandler.js @@ -14,7 +14,7 @@ const OHIFDicomRTStructSopClassHandler = { id: 'OHIFDicomRTStructSopClassHandler', type: MODULE_TYPES.SOP_CLASS_HANDLER, sopClassUIDs, - getDisplaySetFromSeries: function ( + getDisplaySetFromSeries: function( series, study, dicomWebClient, @@ -67,7 +67,7 @@ const OHIFDicomRTStructSopClassHandler = { } } - rtStructDisplaySet.load = function (referencedDisplaySet, studies) { + rtStructDisplaySet.load = function(referencedDisplaySet, studies) { return loadRTStruct( rtStructDisplaySet, referencedDisplaySet, diff --git a/extensions/dicom-rt/src/components/LoadingIndicator/LoadingIndicator.js b/extensions/dicom-rt/src/components/LoadingIndicator/LoadingIndicator.js index beb5d8219..74183677a 100644 --- a/extensions/dicom-rt/src/components/LoadingIndicator/LoadingIndicator.js +++ b/extensions/dicom-rt/src/components/LoadingIndicator/LoadingIndicator.js @@ -1,56 +1,262 @@ import React from 'react'; -const LoadingIndicator = ({ height = "200px", width = "200px", expand = false }) => { +const LoadingIndicator = ({ + height = '200px', + width = '200px', + expand = false, +}) => { return ( -
- +
+ - - + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + diff --git a/extensions/dicom-rt/src/components/PanelSection/PanelSection.js b/extensions/dicom-rt/src/components/PanelSection/PanelSection.js index e193b1546..1a7acbb99 100644 --- a/extensions/dicom-rt/src/components/PanelSection/PanelSection.js +++ b/extensions/dicom-rt/src/components/PanelSection/PanelSection.js @@ -12,8 +12,8 @@ const PanelSection = ({ expanded = false, loading = false, hideVisibleButton = false, - onVisibilityChange = () => { }, - onExpandChange = () => { } + onVisibilityChange = () => {}, + onExpandChange = () => {}, }) => { const [isExpanded, setIsExpanded] = useState(expanded); const [isVisible, setIsVisible] = useState(visible); @@ -27,7 +27,7 @@ const PanelSection = ({ className="dcmrt-panel-section" style={{ marginBottom: isExpanded ? 0 : 2, - height: isExpanded ? '100%' : 'unset' + height: isExpanded ? '100%' : 'unset', }} >
@@ -36,7 +36,7 @@ const PanelSection = ({ {!hideVisibleButton && ( { @@ -47,7 +47,9 @@ const PanelSection = ({ /> )}
- {loading && isExpanded && } + {loading && isExpanded && ( + + )} {children}
); @@ -70,13 +74,13 @@ PanelSection.propTypes = { children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired, visible: PropTypes.bool, expanded: PropTypes.bool, - onVisibilityChange: PropTypes.func + onVisibilityChange: PropTypes.func, }; PanelSection.defaultProps = { visible: false, expanded: false, - onVisibilityChange: () => { } + onVisibilityChange: () => {}, }; export default PanelSection; diff --git a/extensions/dicom-rt/src/components/RTPanel/RTPanel.js b/extensions/dicom-rt/src/components/RTPanel/RTPanel.js index e6399bb02..384794315 100644 --- a/extensions/dicom-rt/src/components/RTPanel/RTPanel.js +++ b/extensions/dicom-rt/src/components/RTPanel/RTPanel.js @@ -31,7 +31,13 @@ const refreshViewport = () => { * @param {number} props.isOpen - isOpen * @returns component */ -const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick }) => { +const RTPanel = ({ + studies, + viewports, + activeIndex, + isOpen, + onContourItemClick, +}) => { const [selectedContour, setSelectedContour] = useState(); const DEFAULT_SET_INDEX = 0; const DEFAULT_STATE = { @@ -65,7 +71,10 @@ const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick } document.addEventListener('extensiondicomrtrtloaded', updateStructureSets); return () => { - document.removeEventListener('extensiondicomrtrtloaded', updateStructureSets); + document.removeEventListener( + 'extensiondicomrtrtloaded', + updateStructureSets + ); }; }, []); @@ -78,7 +87,9 @@ const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick } activeViewport.SeriesInstanceUID ); - const studyMetadata = studyMetadataManager.get(activeViewport.StudyInstanceUID); + const studyMetadata = studyMetadataManager.get( + activeViewport.StudyInstanceUID + ); const referencedDisplaysets = studyMetadata.getDerivedDatasets({ referencedSeriesInstanceUID: activeViewport.SeriesInstanceUID, Modality: 'RTSTRUCT', @@ -89,7 +100,7 @@ const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick } setState({ referencedDisplaysets, selectedSet: defaultSet, - sets: viewportSets + sets: viewportSets, }); } else { setState(DEFAULT_STATE); @@ -105,7 +116,10 @@ const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick } setShowSettings(showSettings && !isOpen); }, [isOpen]); - const toContourItem = ({ ROINumber, ROIName, RTROIObservations, colorArray, visible }, loadedSet) => { + const toContourItem = ( + { ROINumber, ROIName, RTROIObservations, colorArray, visible }, + loadedSet + ) => { let interpretedType = ''; if (RTROIObservations && RTROIObservations.RTROIInterpretedType) { interpretedType = `(${RTROIObservations.RTROIInterpretedType})`; @@ -137,14 +151,20 @@ const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick } ); const frameIndex = imageIds.indexOf(imageId); - const SOPInstanceUID = cornerstone.metaData.get('SOPInstanceUID', imageId); - const StudyInstanceUID = cornerstone.metaData.get('StudyInstanceUID', imageId); + const SOPInstanceUID = cornerstone.metaData.get( + 'SOPInstanceUID', + imageId + ); + const StudyInstanceUID = cornerstone.metaData.get( + 'StudyInstanceUID', + imageId + ); onContourItemClick({ StudyInstanceUID, SOPInstanceUID, frameIndex, - activeViewportIndex: activeIndex + activeViewportIndex: activeIndex, }); }} label={`${ROIName} ${interpretedType}`} @@ -153,7 +173,10 @@ const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick } visible={visible} onVisibilityChange={() => { const module = cornerstoneTools.getModule('rtstruct'); - module.setters.toggleROIContour(state.selectedSet.SeriesInstanceUID, ROINumber); + module.setters.toggleROIContour( + state.selectedSet.SeriesInstanceUID, + ROINumber + ); }} /> ); @@ -189,49 +212,70 @@ const RTPanel = ({ studies, viewports, activeIndex, isOpen, onContourItemClick } onClick={() => setShowSettings(true)} /> - {!state.referencedDisplaysets.length && } - {state.sets && state.referencedDisplaysets.map(displaySet => { - const { SeriesInstanceUID, metadata, isLoaded } = displaySet; + {!state.referencedDisplaysets.length && ( + + )} + {state.sets && + state.referencedDisplaysets.map(displaySet => { + const { SeriesInstanceUID, metadata, isLoaded } = displaySet; - const module = cornerstoneTools.getModule('rtstruct'); - const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(viewports[activeIndex].SeriesInstanceUID); + const module = cornerstoneTools.getModule('rtstruct'); + const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid( + viewports[activeIndex].SeriesInstanceUID + ); - const loadedSet = sets.find(set => set.SeriesInstanceUID === SeriesInstanceUID); - return ( - { - const module = cornerstoneTools.getModule('rtstruct'); - loadedSet.ROIContours.forEach(({ ROINumber }) => { - module.setters.toggleROIContour(loadedSet.SeriesInstanceUID, ROINumber); - }); - const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(viewports[activeIndex].SeriesInstanceUID); - setState(state => ({ ...state, sets })); - refreshViewport(); - }} - onExpandChange={async () => { - if (!isLoaded) { - await displaySet.load(viewports[activeIndex], studies); - const module = cornerstoneTools.getModule('rtstruct'); - const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(viewports[activeIndex].SeriesInstanceUID); - const selectedSet = sets.find(set => set.SeriesInstanceUID === SeriesInstanceUID); - setState(state => ({ ...state, selectedSet, sets })); + const loadedSet = sets.find( + set => set.SeriesInstanceUID === SeriesInstanceUID + ); + return ( + - - - {isLoaded && loadedSet.ROIContours.map(c => toContourItem(c, loadedSet))} - - - - ); - })} + onVisibilityChange={newVisibility => { + const module = cornerstoneTools.getModule('rtstruct'); + loadedSet.ROIContours.forEach(({ ROINumber }) => { + module.setters.toggleROIContour( + loadedSet.SeriesInstanceUID, + ROINumber + ); + }); + const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid( + viewports[activeIndex].SeriesInstanceUID + ); + setState(state => ({ ...state, sets })); + refreshViewport(); + }} + onExpandChange={async () => { + if (!isLoaded) { + await displaySet.load(viewports[activeIndex], studies); + const module = cornerstoneTools.getModule('rtstruct'); + const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid( + viewports[activeIndex].SeriesInstanceUID + ); + const selectedSet = sets.find( + set => set.SeriesInstanceUID === SeriesInstanceUID + ); + setState(state => ({ ...state, selectedSet, sets })); + } + }} + > + + + {isLoaded && + loadedSet.ROIContours.map(c => toContourItem(c, loadedSet))} + + + + ); + })} ); }; diff --git a/extensions/dicom-rt/src/components/RTSettings/RTSettings.js b/extensions/dicom-rt/src/components/RTSettings/RTSettings.js index 1975f2bb3..0fe1a08e6 100644 --- a/extensions/dicom-rt/src/components/RTSettings/RTSettings.js +++ b/extensions/dicom-rt/src/components/RTSettings/RTSettings.js @@ -15,9 +15,7 @@ const RTSettings = ({ configuration, onBack, onChange }) => { return (
{title}
-
- {children} -
+
{children}
); }; @@ -61,8 +59,10 @@ const RTSettings = ({ configuration, onBack, onChange }) => { RTSettings.propTypes = { configuration: PropTypes.shape({ - lineWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - opacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + lineWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) + .isRequired, + opacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) + .isRequired, }).isRequired, onBack: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, diff --git a/extensions/dicom-rt/src/components/StructureSetItem/StructureSetItem.js b/extensions/dicom-rt/src/components/StructureSetItem/StructureSetItem.js index ba3066462..87fd1b047 100644 --- a/extensions/dicom-rt/src/components/StructureSetItem/StructureSetItem.js +++ b/extensions/dicom-rt/src/components/StructureSetItem/StructureSetItem.js @@ -31,7 +31,7 @@ const StructureSetItem = ({ useEffect(() => { setIsVisible(visible); - }, [visible]) + }, [visible]); return (
@@ -99,7 +99,7 @@ StructureSetItem.propTypes = { StructureSetItem.defaultProps = { itemClass: '', - onClick: () => { }, + onClick: () => {}, }; export default StructureSetItem; diff --git a/extensions/dicom-rt/src/loadRTStruct.js b/extensions/dicom-rt/src/loadRTStruct.js index 659f2087a..8ad6c7bf3 100644 --- a/extensions/dicom-rt/src/loadRTStruct.js +++ b/extensions/dicom-rt/src/loadRTStruct.js @@ -68,7 +68,6 @@ export default async function loadRTStruct( const rtStructDisplayToolName = TOOL_NAMES.RTSTRUCT_DISPLAY_TOOL; for (let i = 0; i < ROIContourSequence.length; i++) { - const ROIContour = ROIContourSequence[i]; const { ReferencedROINumber, ContourSequence } = ROIContour; diff --git a/extensions/dicom-rt/src/tools/RTStructDisplayTool.js b/extensions/dicom-rt/src/tools/RTStructDisplayTool.js index 85da79f76..9860cc8cf 100644 --- a/extensions/dicom-rt/src/tools/RTStructDisplayTool.js +++ b/extensions/dicom-rt/src/tools/RTStructDisplayTool.js @@ -70,9 +70,7 @@ export default class RTStructDisplayTool extends BaseTool { } const colorArray = ROIContourData.colorArray; - const color = `rgba(${colorArray[0]},${colorArray[1]},${ - colorArray[2] - },${opacity})`; + const color = `rgba(${colorArray[0]},${colorArray[1]},${colorArray[2]},${opacity})`; lineWidth; diff --git a/extensions/dicom-rt/src/tools/modules/lib/structureSetReferencesSeriesInstanceUid.js b/extensions/dicom-rt/src/tools/modules/lib/structureSetReferencesSeriesInstanceUid.js index 9d8807fbe..4b1906dd6 100644 --- a/extensions/dicom-rt/src/tools/modules/lib/structureSetReferencesSeriesInstanceUid.js +++ b/extensions/dicom-rt/src/tools/modules/lib/structureSetReferencesSeriesInstanceUid.js @@ -10,8 +10,6 @@ export default function structureSetReferencesSeriesInstanceUid( ) { const { referencedSeriesSequence } = StructureSet; return referencedSeriesSequence.some( - referencedSeries => - referencedSeries.SeriesInstanceUID === - SeriesInstanceUID + referencedSeries => referencedSeries.SeriesInstanceUID === SeriesInstanceUID ); } diff --git a/extensions/dicom-rt/src/tools/modules/rtStructModule.js b/extensions/dicom-rt/src/tools/modules/rtStructModule.js index e00ed1074..8b3711b7f 100644 --- a/extensions/dicom-rt/src/tools/modules/rtStructModule.js +++ b/extensions/dicom-rt/src/tools/modules/rtStructModule.js @@ -154,15 +154,10 @@ function setToggleROIContour(SeriesInstanceUID, ROINumber) { * Returns an array of StructureSets which reference the given SeriesInstanceUID. * @param {string} SeriesInstanceUID The SeriesInstanceUID to check. */ -function getStructuresSetsWhichReferenceSeriesInstanceUid( - SeriesInstanceUID -) { +function getStructuresSetsWhichReferenceSeriesInstanceUid(SeriesInstanceUID) { const { StructureSets } = state; return StructureSets.filter(StructureSet => - structureSetReferencesSeriesInstanceUid( - StructureSet, - SeriesInstanceUID - ) + structureSetReferencesSeriesInstanceUid(StructureSet, SeriesInstanceUID) ); } diff --git a/extensions/dicom-segmentation/src/components/BrushColorSelector/BrushColorSelector.js b/extensions/dicom-segmentation/src/components/BrushColorSelector/BrushColorSelector.js index 37593dd51..75686694f 100644 --- a/extensions/dicom-segmentation/src/components/BrushColorSelector/BrushColorSelector.js +++ b/extensions/dicom-segmentation/src/components/BrushColorSelector/BrushColorSelector.js @@ -12,12 +12,8 @@ const BrushColorSelector = ({ defaultColor, index, onNext, onPrev }) => ( {index}
- - + +
); diff --git a/extensions/dicom-segmentation/src/components/BrushRadius/BrushRadius.js b/extensions/dicom-segmentation/src/components/BrushRadius/BrushRadius.js index 822465941..1f0aee1ec 100644 --- a/extensions/dicom-segmentation/src/components/BrushRadius/BrushRadius.js +++ b/extensions/dicom-segmentation/src/components/BrushRadius/BrushRadius.js @@ -27,7 +27,7 @@ BrushRadius.propTypes = { }; BrushRadius.defaultProps = { - onChange: () => { }, + onChange: () => {}, min: 1, max: 50, step: 1, diff --git a/extensions/dicom-segmentation/src/components/SegmentItem/SegmentItem.js b/extensions/dicom-segmentation/src/components/SegmentItem/SegmentItem.js index 9d405e8e9..2e44e27dc 100644 --- a/extensions/dicom-segmentation/src/components/SegmentItem/SegmentItem.js +++ b/extensions/dicom-segmentation/src/components/SegmentItem/SegmentItem.js @@ -17,7 +17,15 @@ ColoredCircle.propTypes = { color: PropTypes.array.isRequired, }; -const SegmentItem = ({ index, label, onClick, itemClass, color, visible = true, onVisibilityChange }) => { +const SegmentItem = ({ + index, + label, + onClick, + itemClass, + color, + visible = true, + onVisibilityChange, +}) => { const [isVisible, setIsVisible] = useState(visible); useEffect(() => { @@ -61,7 +69,7 @@ const SegmentItem = ({ index, label, onClick, itemClass, color, visible = true, - Relabel + Relabel )} @@ -90,7 +98,7 @@ SegmentItem.propTypes = { SegmentItem.defaultProps = { itemClass: '', - onClick: () => { } + onClick: () => {}, }; export default SegmentItem; diff --git a/extensions/dicom-segmentation/src/components/SegmentationItem/SegmentationItem.js b/extensions/dicom-segmentation/src/components/SegmentationItem/SegmentationItem.js index 015330bd6..590541876 100644 --- a/extensions/dicom-segmentation/src/components/SegmentationItem/SegmentationItem.js +++ b/extensions/dicom-segmentation/src/components/SegmentationItem/SegmentationItem.js @@ -21,7 +21,7 @@ SegmentationItem.propTypes = { }; SegmentationItem.defaultProps = { - description: '' + description: '', }; export default SegmentationItem; diff --git a/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js b/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js index 084f7a0c9..ae751022a 100644 --- a/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js +++ b/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js @@ -68,8 +68,7 @@ const SegmentationPanel = ({ */ const [state, setState] = useState({ brushRadius: DEFAULT_BRUSH_RADIUS, - brushColor: - 'rgba(221, 85, 85, 1)', + brushColor: 'rgba(221, 85, 85, 1)', selectedSegment: null, selectedSegmentation: null, showSegmentationSettings: false, @@ -77,7 +76,7 @@ const SegmentationPanel = ({ labelmapList: [], segmentList: [], cachedSegmentsProperties: [], - isLoading: false + isLoading: false, }); useEffect(() => { @@ -111,7 +110,10 @@ const SegmentationPanel = ({ * allows us to easily watch the module or the segmentations loading process in any other component * without subscribing to external events. */ - document.addEventListener('extensiondicomsegmentationsegloaded', refreshSegmentations); + document.addEventListener( + 'extensiondicomsegmentationsegloaded', + refreshSegmentations + ); /* * These are specific to each element; @@ -126,7 +128,10 @@ const SegmentationPanel = ({ ); return () => { - document.removeEventListener('extensiondicomsegmentationsegloaded', refreshSegmentations); + document.removeEventListener( + 'extensiondicomsegmentationsegloaded', + refreshSegmentations + ); cornerstoneTools.store.state.enabledElements.forEach(enabledElement => enabledElement.removeEventListener( 'cornerstonetoolslabelmapmodified', @@ -173,15 +178,17 @@ const SegmentationPanel = ({ segmentList: [], })); } - }, [ - viewports, - activeIndex, - state.isLoading - ]); + }, [viewports, activeIndex, state.isLoading]); useEffect(() => { refreshSegmentations(); - }, [viewports, activeIndex, state.selectedSegmentation, activeContexts, state.isLoading]); + }, [ + viewports, + activeIndex, + state.selectedSegmentation, + activeContexts, + state.isLoading, + ]); /* Handle open/closed panel behaviour */ useEffect(() => { @@ -369,9 +376,13 @@ const SegmentationPanel = ({ return !segmentsHidden[segmentIndex]; }; - const cachedSegmentProperties = state.cachedSegmentsProperties[segmentNumber]; + const cachedSegmentProperties = + state.cachedSegmentsProperties[segmentNumber]; let visible = isSegmentVisible(); - if (cachedSegmentProperties && cachedSegmentProperties.visible !== visible) { + if ( + cachedSegmentProperties && + cachedSegmentProperties.visible !== visible + ) { toggleSegmentVisibility(); } @@ -399,7 +410,9 @@ const SegmentationPanel = ({ onSegmentVisibilityChange(segmentNumber, newVisibility); } - updateCachedSegmentsProperties(segmentNumber, { visible: newVisibility }); + updateCachedSegmentsProperties(segmentNumber, { + visible: newVisibility, + }); refreshViewport(); }} /> @@ -422,10 +435,9 @@ const SegmentationPanel = ({ const segmentsProperties = state.cachedSegmentsProperties; const segmentProperties = state.cachedSegmentsProperties[segmentNumber]; - segmentsProperties[segmentNumber] = - segmentProperties ? - { ...segmentProperties, ...properties } : - properties; + segmentsProperties[segmentNumber] = segmentProperties + ? { ...segmentProperties, ...properties } + : properties; updateState('cachedSegmentsProperties', segmentsProperties); }; @@ -495,7 +507,10 @@ const SegmentationPanel = ({ refreshViewport(); }; - const disabledConfigurationFields = ['outlineAlpha', 'shouldRenderInactiveLabelmaps']; + const disabledConfigurationFields = [ + 'outlineAlpha', + 'shouldRenderInactiveLabelmaps', + ]; if (state.showSegmentationSettings) { return ( { }, + callback = () => {}, onDisplaySetLoadFailure ) => { if (displaySet.labelmapIndex === activeLabelmapIndex) { diff --git a/extensions/dicom-segmentation/src/components/SegmentationSelect.js b/extensions/dicom-segmentation/src/components/SegmentationSelect.js index 52b2ca8f0..fde946211 100644 --- a/extensions/dicom-segmentation/src/components/SegmentationSelect.js +++ b/extensions/dicom-segmentation/src/components/SegmentationSelect.js @@ -19,7 +19,7 @@ const uiGrayDark = computedstyle.getPropertyValue('--ui-gray-dark'); const segmentationSelectStyles = { singleValue: (base, state) => ({ ...base, - width: '100%' + width: '100%', }), control: (base, state) => ({ ...base, diff --git a/extensions/dicom-segmentation/src/components/SegmentationSettings/SegmentationSettings.js b/extensions/dicom-segmentation/src/components/SegmentationSettings/SegmentationSettings.js index 3d637b80f..cbff64d3d 100644 --- a/extensions/dicom-segmentation/src/components/SegmentationSettings/SegmentationSettings.js +++ b/extensions/dicom-segmentation/src/components/SegmentationSettings/SegmentationSettings.js @@ -4,7 +4,12 @@ import { Range } from '@ohif/ui'; import './SegmentationSettings.css'; -const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields = [] }) => { +const SegmentationSettings = ({ + configuration, + onBack, + onChange, + disabledFields = [], +}) => { const [state, setState] = useState({ renderFill: configuration.renderFill, renderOutline: configuration.renderOutline, @@ -13,7 +18,7 @@ const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields outlineAlpha: configuration.outlineAlpha, outlineWidth: configuration.outlineWidth, fillAlphaInactive: configuration.fillAlphaInactive, - outlineAlphaInactive: configuration.outlineAlphaInactive + outlineAlphaInactive: configuration.outlineAlphaInactive, }); useEffect(() => { @@ -78,7 +83,9 @@ const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields step={1} min={0} max={100} - onChange={event => save('outlineAlpha', toFloat(event.target.value))} + onChange={event => + save('outlineAlpha', toFloat(event.target.value)) + } /> )} {!disabledFields.includes('outlineWidth') && ( @@ -89,50 +96,64 @@ const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields step={1} min={0} max={5} - onChange={event => save('outlineWidth', parseInt(event.target.value))} + onChange={event => + save('outlineWidth', parseInt(event.target.value)) + } /> )} )} - {(state.renderFill || state.renderOutline) && !disabledFields.includes('shouldRenderInactiveLabelmaps') && ( -
- check('shouldRenderInactiveLabelmaps')} - /> - {state.shouldRenderInactiveLabelmaps && ( - <> - {state.renderFill && !disabledFields.includes('fillAlphaInactive') && ( - save('fillAlphaInactive', toFloat(event.target.value))} - /> - )} - {state.renderOutline && !disabledFields.includes('outlineAlphaInactive') && ( - save('outlineAlphaInactive', toFloat(event.target.value))} - /> - )} - - )} -
- )} + {(state.renderFill || state.renderOutline) && + !disabledFields.includes('shouldRenderInactiveLabelmaps') && ( +
+ check('shouldRenderInactiveLabelmaps')} + /> + {state.shouldRenderInactiveLabelmaps && ( + <> + {state.renderFill && + !disabledFields.includes('fillAlphaInactive') && ( + + save('fillAlphaInactive', toFloat(event.target.value)) + } + /> + )} + {state.renderOutline && + !disabledFields.includes('outlineAlphaInactive') && ( + + save( + 'outlineAlphaInactive', + toFloat(event.target.value) + ) + } + /> + )} + + )} +
+ )} ); }; @@ -169,8 +190,10 @@ SegmentationSettings.propTypes = { renderFill: PropTypes.bool.isRequired, renderOutline: PropTypes.bool.isRequired, shouldRenderInactiveLabelmaps: PropTypes.bool.isRequired, - fillAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, /* TODO: why fillAlpha is string? */ - outlineAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, /* TODO: why fillAlpha is string? */ + fillAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + .isRequired /* TODO: why fillAlpha is string? */, + outlineAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + .isRequired /* TODO: why fillAlpha is string? */, outlineWidth: PropTypes.number.isRequired, fillAlphaInactive: PropTypes.number.isRequired, outlineAlphaInactive: PropTypes.number.isRequired, diff --git a/extensions/dicom-segmentation/src/index.js b/extensions/dicom-segmentation/src/index.js index 0eb6ef545..a01184b66 100644 --- a/extensions/dicom-segmentation/src/index.js +++ b/extensions/dicom-segmentation/src/index.js @@ -46,7 +46,7 @@ export default { const onSegmentVisibilityChangeHandler = (segmentNumber, visible) => { commandsManager.runCommand('setSegmentConfiguration', { segmentNumber, - visible + visible, }); }; @@ -55,7 +55,7 @@ export default { globalOpacity: configuration.fillAlpha, outlineThickness: configuration.outlineWidth, renderOutline: configuration.renderOutline, - visible: configuration.renderFill + visible: configuration.renderFill, }); }; diff --git a/extensions/vtk/src/LoadingIndicator.js b/extensions/vtk/src/LoadingIndicator.js index 953c5e45f..0c24b3d6a 100644 --- a/extensions/vtk/src/LoadingIndicator.js +++ b/extensions/vtk/src/LoadingIndicator.js @@ -32,16 +32,16 @@ class LoadingIndicator extends PureComponent { ) : ( -
-
-

- {this.props.t('Loading...')} - - {percComplete} -

-
+
+
+

+ {this.props.t('Loading...')} + + {percComplete} +

- )} +
+ )} ); } diff --git a/extensions/vtk/src/OHIFVTKViewport.js b/extensions/vtk/src/OHIFVTKViewport.js index 5f864ba2b..6288cb9a0 100644 --- a/extensions/vtk/src/OHIFVTKViewport.js +++ b/extensions/vtk/src/OHIFVTKViewport.js @@ -49,7 +49,7 @@ class OHIFVTKViewport extends Component { state = { volumes: null, paintFilterLabelMapImageData: null, - paintFilterBackgroundImageData: null + paintFilterBackgroundImageData: null, }; static propTypes = { @@ -69,7 +69,7 @@ class OHIFVTKViewport extends Component { }; static defaultProps = { - onScroll: () => { }, + onScroll: () => {}, }; static id = 'OHIFVTKViewport'; @@ -156,9 +156,11 @@ class OHIFVTKViewport extends Component { const { activeLabelmapIndex } = brushStackState; const labelmap3D = brushStackState.labelmaps3D[activeLabelmapIndex]; - this.segmentsDefaultProperties = labelmap3D.segmentsHidden.map(isHidden => { - return { visible: !isHidden }; - }); + this.segmentsDefaultProperties = labelmap3D.segmentsHidden.map( + isHidden => { + return { visible: !isHidden }; + } + ); const vtkLabelmapID = `${firstImageId}_${activeLabelmapIndex}`; @@ -349,7 +351,7 @@ class OHIFVTKViewport extends Component { if ( displaySet.displaySetInstanceUID !== - prevDisplaySet.displaySetInstanceUID || + prevDisplaySet.displaySetInstanceUID || displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID || displaySet.frameIndex !== prevDisplaySet.frameIndex ) { @@ -435,7 +437,7 @@ class OHIFVTKViewport extends Component { segmentsDefaultProperties: this.segmentsDefaultProperties, onNewSegmentationRequested: () => { this.setStateFromProps(); - } + }, }} onScroll={this.props.onScroll} /> diff --git a/extensions/vtk/src/commandsModule.js b/extensions/vtk/src/commandsModule.js index e2b110c42..c43ba3c99 100644 --- a/extensions/vtk/src/commandsModule.js +++ b/extensions/vtk/src/commandsModule.js @@ -165,7 +165,7 @@ const commandsModule = ({ commandsManager }) => { segmentNumber, frameIndex, frame, - done = () => { } + done = () => {}, }) => { let api = apis[viewports.activeViewportIndex]; @@ -180,10 +180,13 @@ const commandsModule = ({ commandsManager }) => { displaySetInstanceUID, SOPClassUID, SOPInstanceUID, - frameIndex, + frameIndex ); - const imageDataObject = getImageData(stack.imageIds, displaySetInstanceUID); + const imageDataObject = getImageData( + stack.imageIds, + displaySetInstanceUID + ); let pixelIndex = 0; let x = 0; @@ -209,7 +212,10 @@ const commandsModule = ({ commandsManager }) => { y /= count; const position = [x, y, frameIndex]; - const worldPos = _convertModelToWorldSpace(position, imageDataObject.vtkImageData); + const worldPos = _convertModelToWorldSpace( + position, + imageDataObject.vtkImageData + ); api.svgWidgets.crosshairsWidget.moveCrosshairs(worldPos, apis); done(); diff --git a/extensions/vtk/src/toolbarComponents/VTKMPRToolbarButton.js b/extensions/vtk/src/toolbarComponents/VTKMPRToolbarButton.js index 82ebbc5e6..617a0e8d6 100644 --- a/extensions/vtk/src/toolbarComponents/VTKMPRToolbarButton.js +++ b/extensions/vtk/src/toolbarComponents/VTKMPRToolbarButton.js @@ -8,10 +8,13 @@ const { studyMetadataManager } = utils; let isVisible = true; -const _isDisplaySetReconstructable = (viewportSpecificData = {}, activeViewportIndex) => { +const _isDisplaySetReconstructable = ( + viewportSpecificData = {}, + activeViewportIndex +) => { if (!viewportSpecificData[activeViewportIndex]) { return false; - }; + } const { displaySetInstanceUID, StudyInstanceUID } = viewportSpecificData[ activeViewportIndex @@ -27,11 +30,13 @@ const _isDisplaySetReconstructable = (viewportSpecificData = {}, activeViewportI return false; } - const displaySet = study._displaySets.find(set => set.displaySetInstanceUID === displaySetInstanceUID); + const displaySet = study._displaySets.find( + set => set.displaySetInstanceUID === displaySetInstanceUID + ); if (!displaySet) { return false; - }; + } return displaySet.isReconstructable; }; @@ -52,12 +57,12 @@ function VTKMPRToolbarButton({ return { viewportSpecificData, activeViewportIndex, - } + }; }); isVisible = _isDisplaySetReconstructable( viewportSpecificData, - activeViewportIndex, + activeViewportIndex ); return ( diff --git a/extensions/vtk/src/toolbarModule.js b/extensions/vtk/src/toolbarModule.js index 9cfa49f63..832acae34 100644 --- a/extensions/vtk/src/toolbarModule.js +++ b/extensions/vtk/src/toolbarModule.js @@ -131,4 +131,4 @@ const definitions = [ export default { definitions, defaultContext: 'ACTIVE_VIEWPORT::VTK', -} +}; diff --git a/platform/core/package.json b/platform/core/package.json index fa97ec8da..83320ad2f 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -39,7 +39,8 @@ "@babel/runtime": "7.7.6", "ajv": "^6.10.0", "dcmjs": "^0.12.4", - "dicomweb-client": "^0.5.2", + "dicomweb-client": "^0.6.0", + "immer": "6.0.2", "isomorphic-base64": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.merge": "^4.6.1", diff --git a/platform/core/src/classes/metadata/StudyMetadata.js b/platform/core/src/classes/metadata/StudyMetadata.js index a33c3dfe5..911427f67 100644 --- a/platform/core/src/classes/metadata/StudyMetadata.js +++ b/platform/core/src/classes/metadata/StudyMetadata.js @@ -79,7 +79,7 @@ export class StudyMetadata extends Metadata { Object.defineProperty(this, 'studyInstanceUID', { configurable: false, enumerable: false, - get: function () { + get: function() { return this.getStudyInstanceUID(); }, }); diff --git a/platform/core/src/extensions/ExtensionManager.js b/platform/core/src/extensions/ExtensionManager.js index 954a50ed1..0e91754f4 100644 --- a/platform/core/src/extensions/ExtensionManager.js +++ b/platform/core/src/extensions/ExtensionManager.js @@ -182,7 +182,7 @@ export default class ExtensionManager { commandsManager: this._commandsManager, appConfig: this._appConfig, configuration, - api: this._api + api: this._api, }); if (!extensionModule) { diff --git a/platform/core/src/index.js b/platform/core/src/index.js index 1f9e42de7..8e8da6ed1 100644 --- a/platform/core/src/index.js +++ b/platform/core/src/index.js @@ -7,6 +7,7 @@ import classes, { CommandsManager, HotkeysManager } from './classes/'; import DICOMWeb from './DICOMWeb'; import DICOMSR from './DICOMSR'; import cornerstone from './cornerstone.js'; +import errorHandler from './errorHandler.js'; import hangingProtocols from './hanging-protocols'; import header from './header.js'; import log from './log.js'; diff --git a/platform/core/src/redux/index.test.js b/platform/core/src/redux/index.test.js index 748adfcaa..c2e16c288 100644 --- a/platform/core/src/redux/index.test.js +++ b/platform/core/src/redux/index.test.js @@ -2,7 +2,12 @@ import redux from './index.js'; describe('redux exports', () => { test('have not changed', () => { - const expectedExports = ['actions', 'reducers', 'localStorage', 'sessionStorage'].sort(); + const expectedExports = [ + 'actions', + 'reducers', + 'localStorage', + 'sessionStorage', + ].sort(); const exports = Object.keys(redux).sort(); diff --git a/platform/core/src/services/MeasurementService/MeasurementService.test.js b/platform/core/src/services/MeasurementService/MeasurementService.test.js index 5b24b54a0..1304c1e19 100644 --- a/platform/core/src/services/MeasurementService/MeasurementService.test.js +++ b/platform/core/src/services/MeasurementService/MeasurementService.test.js @@ -34,7 +34,10 @@ describe('MeasurementService.js', () => { unit: 'mm', area: 123, type: measurementService.VALUE_TYPES.POLYLINE, - points: [{ x: 1, y: 2 }, { x: 1, y: 2 }], + points: [ + { x: 1, y: 2 }, + { x: 1, y: 2 }, + ], source: source, }; toAnnotation = () => annotation; diff --git a/platform/core/src/utils/Queue.js b/platform/core/src/utils/Queue.js index 78ee04684..afe64cc00 100644 --- a/platform/core/src/utils/Queue.js +++ b/platform/core/src/utils/Queue.js @@ -1,6 +1,4 @@ - export default class Queue { - constructor(limit) { this.limit = limit; this.size = 0; diff --git a/platform/core/src/utils/isDisplaySetReconstructable.js b/platform/core/src/utils/isDisplaySetReconstructable.js index 0f5912706..0d0f250b1 100644 --- a/platform/core/src/utils/isDisplaySetReconstructable.js +++ b/platform/core/src/utils/isDisplaySetReconstructable.js @@ -167,8 +167,8 @@ function _getSpacingIssue(spacing, averageSpacing) { function _getPerpendicularDistance(a, b) { return Math.sqrt( Math.pow(a[0] - b[0], 2) + - Math.pow(a[1] - b[1], 2) + - Math.pow(a[2] - b[2], 2) + Math.pow(a[1] - b[1], 2) + + Math.pow(a[2] - b[2], 2) ); } diff --git a/platform/core/src/utils/makeDeferred.js b/platform/core/src/utils/makeDeferred.js index 0f5a0fa9f..8becf3295 100644 --- a/platform/core/src/utils/makeDeferred.js +++ b/platform/core/src/utils/makeDeferred.js @@ -1,7 +1,9 @@ export default function makeDeferred() { - let reject, resolve, promise = new Promise(function (res, rej) { - resolve = res; - reject = rej; - }); + let reject, + resolve, + promise = new Promise(function(res, rej) { + resolve = res; + reject = rej; + }); return Object.freeze({ promise, resolve, reject }); } diff --git a/platform/core/src/utils/metadataProvider/fetchPaletteColorLookupTableData.js b/platform/core/src/utils/metadataProvider/fetchPaletteColorLookupTableData.js index 8aba64ec4..b33a576d9 100644 --- a/platform/core/src/utils/metadataProvider/fetchPaletteColorLookupTableData.js +++ b/platform/core/src/utils/metadataProvider/fetchPaletteColorLookupTableData.js @@ -116,9 +116,8 @@ function _getPaletteColor(server, paletteColorLookupTableData, lutDescriptor) { const bits = lutDescriptor[2]; const arrayBufferToPaletteColorLUT = arraybuffer => { - const byteArray = bits === 16 ? - new Uint16Array(arraybuffer) : - new Uint8Array(arraybuffer); + const byteArray = + bits === 16 ? new Uint16Array(arraybuffer) : new Uint8Array(arraybuffer); const lut = []; for (let i = 0; i < numLutEntries; i++) { diff --git a/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js b/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js index 7d76c39f7..7a89430b7 100644 --- a/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js +++ b/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js @@ -124,7 +124,7 @@ export default function getPixelSpacingInformation(instance) { }; } - log.info( + log.info( 'Unknown combination of PixelSpacing and ImagerPixelSpacing identified. Unable to determine spacing.' ); } diff --git a/platform/i18n/src/locales/ar/index.js b/platform/i18n/src/locales/ar/index.js index dda412a8f..2d37bdc15 100644 --- a/platform/i18n/src/locales/ar/index.js +++ b/platform/i18n/src/locales/ar/index.js @@ -1,7 +1,7 @@ import UserPreferencesModal from './UserPreferencesModal.json'; -export default { - 'ar': { +export default { + ar: { UserPreferencesModal, - } + }, }; diff --git a/platform/i18n/src/locales/en-US/index.js b/platform/i18n/src/locales/en-US/index.js index 48772f9f6..b21c68812 100644 --- a/platform/i18n/src/locales/en-US/index.js +++ b/platform/i18n/src/locales/en-US/index.js @@ -9,7 +9,7 @@ import StudyList from './StudyList.json'; import UserPreferencesModal from './UserPreferencesModal.json'; import ViewportDownloadForm from './ViewportDownloadForm.json'; -export default { +export default { 'en-US': { AboutModal, Buttons, @@ -21,5 +21,5 @@ export default { StudyList, UserPreferencesModal, ViewportDownloadForm, - } + }, }; diff --git a/platform/i18n/src/locales/es/index.js b/platform/i18n/src/locales/es/index.js index 7a988b665..9ac8a8b84 100644 --- a/platform/i18n/src/locales/es/index.js +++ b/platform/i18n/src/locales/es/index.js @@ -6,8 +6,8 @@ import MeasurementTable from './MeasurementTable.json'; import StudyList from './StudyList.json'; import UserPreferencesModal from './UserPreferencesModal.json'; -export default { - 'es': { +export default { + es: { Buttons, CineDialog, Common, @@ -15,5 +15,5 @@ export default { MeasurementTable, StudyList, UserPreferencesModal, - } + }, }; diff --git a/platform/i18n/src/locales/fr/index.js b/platform/i18n/src/locales/fr/index.js index 8af9acd97..2fabaff3a 100644 --- a/platform/i18n/src/locales/fr/index.js +++ b/platform/i18n/src/locales/fr/index.js @@ -4,12 +4,12 @@ import Common from './Common.json'; import Header from './Header.json'; import UserPreferencesModal from './UserPreferencesModal.json'; -export default { - 'fr': { +export default { + fr: { Buttons, CineDialog, Common, Header, UserPreferencesModal, - } + }, }; diff --git a/platform/i18n/src/locales/ja-JP/index.js b/platform/i18n/src/locales/ja-JP/index.js index b116df893..38f2661d7 100644 --- a/platform/i18n/src/locales/ja-JP/index.js +++ b/platform/i18n/src/locales/ja-JP/index.js @@ -4,12 +4,12 @@ import Common from './Common.json'; import Header from './Header.json'; import UserPreferencesModal from './UserPreferencesModal.json'; -export default { +export default { 'ja-JP': { Buttons, CineDialog, Common, Header, UserPreferencesModal, - } + }, }; diff --git a/platform/i18n/src/locales/nl/index.js b/platform/i18n/src/locales/nl/index.js index fa22d5d06..de42f561e 100644 --- a/platform/i18n/src/locales/nl/index.js +++ b/platform/i18n/src/locales/nl/index.js @@ -2,10 +2,10 @@ import Buttons from './Buttons.json'; import Common from './Common.json'; import Header from './Header.json'; -export default { - 'nl': { +export default { + nl: { Buttons, Common, Header, - } + }, }; diff --git a/platform/i18n/src/locales/pt-BR/index.js b/platform/i18n/src/locales/pt-BR/index.js index 8b1cef147..1b37dc9a6 100644 --- a/platform/i18n/src/locales/pt-BR/index.js +++ b/platform/i18n/src/locales/pt-BR/index.js @@ -6,7 +6,7 @@ import DatePicker from './DatePicker.json'; import Header from './Header.json'; import UserPreferencesModal from './UserPreferencesModal.json'; -export default { +export default { 'pt-BR': { AboutModal, Buttons, @@ -15,5 +15,5 @@ export default { DatePicker, Header, UserPreferencesModal, - } + }, }; diff --git a/platform/i18n/src/locales/vi/index.js b/platform/i18n/src/locales/vi/index.js index a8e3c0175..93283fddb 100644 --- a/platform/i18n/src/locales/vi/index.js +++ b/platform/i18n/src/locales/vi/index.js @@ -5,13 +5,13 @@ import Header from './Header.json'; import StudyList from './StudyList.json'; import UserPreferencesModal from './UserPreferencesModal.json'; -export default { - 'vi': { +export default { + vi: { Buttons, CineDialog, Common, Header, StudyList, UserPreferencesModal, - } + }, }; diff --git a/platform/i18n/src/locales/zh/index.js b/platform/i18n/src/locales/zh/index.js index 049565bd6..35a0a2f72 100644 --- a/platform/i18n/src/locales/zh/index.js +++ b/platform/i18n/src/locales/zh/index.js @@ -6,8 +6,8 @@ import MeasurementTable from './MeasurementTable.json'; import StudyList from './StudyList.json'; import UserPreferencesModal from './UserPreferencesModal.json'; -export default { - 'zh': { +export default { + zh: { Buttons, CineDialog, Common, @@ -15,5 +15,5 @@ export default { MeasurementTable, StudyList, UserPreferencesModal, - } + }, }; diff --git a/platform/ui/README.md b/platform/ui/README.md index 6a871d0e7..b31eafafc 100644 --- a/platform/ui/README.md +++ b/platform/ui/README.md @@ -1,46 +1,3 @@ -<<<<<<< HEAD -# Basic Docz example - -## Using `create-docz-app` - -```sh -npx create-docz-app docz-app-basic -# or -yarn create docz-app docz-app-basic -``` - -## Download manually - -```sh -curl https://codeload.github.com/doczjs/docz/tar.gz/master | tar -xz --strip=2 docz-master/examples/basic -mv basic docz-basic-example -cd docz-basic-example -``` - -## Setup - -```sh -yarn # npm i -``` - -## Run - -```sh -yarn dev # npm run dev -``` - -## Build - -```sh -yarn build # npm run build -``` - -## Serve built app - -```sh -yarn serve # npm run serve -``` -======= # @ohif/ui React component library powered by `docz` @@ -60,4 +17,3 @@ yarn build # npm run build # Serve (the "build" output) yarn serve # npm run serve ``` ->>>>>>> 4a8675655... feat: nuke UI project; start new with updated tooling BREAKING_CHANGE (#1468) diff --git a/platform/ui/gatsby-node.js b/platform/ui/gatsby-node.js index 828d7c7ad..308d067ab 100644 --- a/platform/ui/gatsby-node.js +++ b/platform/ui/gatsby-node.js @@ -1,8 +1,11 @@ const path = require('path'); +// ~~ Plugins +const PnpWebpackPlugin = require(`pnp-webpack-plugin`); // Required until Webpack@5 exports.onCreateWebpackConfig = args => { args.actions.setWebpackConfig({ resolve: { + plugins: [PnpWebpackPlugin], // Note the '..' in the path because docz gatsby project lives in the '.docz' directory modules: [ // monorepo root @@ -16,5 +19,8 @@ exports.onCreateWebpackConfig = args => { // symlinks: true, // }, }, + resolveLoader: { + plugins: [PnpWebpackPlugin.moduleLoader(module)], + }, }); }; diff --git a/platform/ui/package.json b/platform/ui/package.json index fc9d0045a..81bc781aa 100644 --- a/platform/ui/package.json +++ b/platform/ui/package.json @@ -19,10 +19,12 @@ ], "scripts": { "start": "yarn run dev", - "build:styles": "postcss src/styles/tailwind.css -o src/gatsby-theme-docz/app.css", - "dev": "docz dev", "build": "docz build", - "serve": "docz serve" + "build:ui:ci": "docz build", + "build:ui:deploy-preview": "docz build --base=/ui/", + "dev": "docz dev", + "serve": "docz serve", + "docs:preview": "yarn run dev" }, "dependencies": { "classnames": "^2.2.6", diff --git a/platform/ui/src/components/Button/Button.jsx b/platform/ui/src/components/Button/Button.jsx index a5b25e2d7..ce5e270af 100644 --- a/platform/ui/src/components/Button/Button.jsx +++ b/platform/ui/src/components/Button/Button.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useRef } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; @@ -6,17 +6,18 @@ const baseClasses = 'leading-none font-sans text-center justify-center items-center outline-none transition duration-300 ease-in-out focus:outline-none'; const defaults = { - variant: 'contained', color: 'default', - size: 'medium', - radius: 'medium', disabled: false, + fullWidth: false, + rounded: 'medium', + size: 'medium', type: 'button', + variant: 'contained', }; -const radiusClasses = { +const roundedClasses = { none: '', - small: 'rounded-sm', + small: 'rounded', medium: 'rounded-md', large: 'rounded-lg', full: 'rounded-full', @@ -77,7 +78,7 @@ const Button = ({ variant = defaults.variant, color = defaults.color, size = defaults.size, - radius = defaults.radius, + rounded = defaults.rounded, disabled = defaults.disabled, type = defaults.type, fullWidth = defaults.fullWidth, @@ -86,14 +87,24 @@ const Button = ({ className, ...rest }) => { - const baseClasses = - 'inline-flex items-center outline-none transition duration-300 ease-in-out font-bold focus:outline-none'; - const startIcon = startIconProp && ( -
{startIconProp}
+
+ {React.cloneElement(startIconProp, { + className: classnames('w-4 h-4 fill-current'), + })} +
); - const handleOnClick = e => { + const endIcon = endIconProp && ( +
+ {React.cloneElement(endIconProp, { + className: classnames('w-4 h-4 fill-current'), + })} +
+ ); + const buttonElement = useRef(null); + + const handleOnClick = (e) => { buttonElement.current.blur(); if (rest.onClick) { rest.onClick(e); @@ -106,11 +117,13 @@ const Button = ({ className, baseClasses, variantClasses[variant][color], - radiusClasses[radius], + roundedClasses[rounded], sizeClasses[size], fullWidthClasses[fullWidth], disabledClasses[disabled] )} + ref={buttonElement} + onClick={handleOnClick} type={type} {...rest} > diff --git a/platform/ui/src/components/Button/Button.mdx b/platform/ui/src/components/Button/Button.mdx index bd5dd8598..3d58bd857 100644 --- a/platform/ui/src/components/Button/Button.mdx +++ b/platform/ui/src/components/Button/Button.mdx @@ -24,10 +24,10 @@ import { Button } from '@ohif/ui'; - -
-## Outlined Buttons +## Contained Buttons
- - -
- - - + + + +
+
+ + +
diff --git a/platform/ui/src/components/DateRange/DateRange.jsx b/platform/ui/src/components/DateRange/DateRange.jsx index a5996d4f6..033a967ab 100644 --- a/platform/ui/src/components/DateRange/DateRange.jsx +++ b/platform/ui/src/components/DateRange/DateRange.jsx @@ -46,7 +46,7 @@ const renderYearsOptions = () => { return options; }; -const DateRange = props => { +const DateRange = (props) => { const { onChange, startDate, endDate } = props; const [focusedInput, setFocusedInput] = useState(null); const renderYearsOptionsCallback = useCallback(renderYearsOptions, []); @@ -82,11 +82,11 @@ const DateRange = props => { onYearSelect: PropTypes.func, }; - const handleMonthChange = event => { + const handleMonthChange = (event) => { onMonthSelect(month, event.target.value); }; - const handleYearChange = event => { + const handleYearChange = (event) => { onYearSelect(month, event.target.value); }; @@ -140,7 +140,7 @@ const DateRange = props => { }) }} focusedInput={focusedInput} - onFocusChange={updatedVal => setFocusedInput(updatedVal)} + onFocusChange={(updatedVal) => setFocusedInput(updatedVal)} /** OPTIONAL */ renderCalendarInfo={renderDatePresets} renderMonthElement={renderMonthElement} @@ -150,7 +150,7 @@ const DateRange = props => { closeDatePicker: 'Close', clearDates: 'Clear dates', }} - isOutsideRange={day => !isInclusivelyBeforeDay(day, moment())} + isOutsideRange={(day) => !isInclusivelyBeforeDay(day, moment())} hideKeyboardShortcutsPanel={true} numberOfMonths={1} showClearDates={false} diff --git a/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx b/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx index 782e57bd7..625d90aa7 100644 --- a/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx +++ b/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx @@ -7,13 +7,13 @@ import { ButtonGroup, Button, StudyItem, ThumbnailList } from '@ohif/ui'; const buttonClasses = 'text-white text-base border-none bg-black p-2 min-w-18'; const activeButtonClasses = 'bg-primary-main'; -const getInitialActiveTab = tabs => { +const getInitialActiveTab = (tabs) => { return tabs && tabs[0] && tabs[0].name; }; -const getTrackedSeries = displaySets => { +const getTrackedSeries = (displaySets) => { let trackedSeries = 0; - displaySets.forEach(displaySet => { + displaySets.forEach((displaySet) => { if (displaySet.isTracked) { trackedSeries++; } @@ -25,9 +25,10 @@ const getTrackedSeries = displaySets => { const StudyBrowser = ({ tabs, onClickStudy, onClickThumbnail }) => { const [tabActive, setTabActive] = useState(getInitialActiveTab(tabs)); const [studyActive, setStudyActive] = useState(null); + const [thumbnailActive, setThumbnailActive] = useState(null); const getTabContent = () => { - const tabData = tabs.find(tab => tab.name === tabActive); + const tabData = tabs.find((tab) => tab.name === tabActive); if (!tabData || !tabData.studies || !Array.isArray(tabData.studies)) { return; @@ -36,9 +37,9 @@ const StudyBrowser = ({ tabs, onClickStudy, onClickThumbnail }) => { return tabData.studies.map( ({ studyInstanceUid, - studyDate, - studyDescription, - instances, + date, + description, + numInstances, modalities, displaySets, }) => { @@ -46,9 +47,9 @@ const StudyBrowser = ({ tabs, onClickStudy, onClickThumbnail }) => { return ( { { - setThumbnailActive( - thumbnailId === thumbnailActive ? null : thumbnailId - ); + onThumbnailClick={(thumbnailId) => { + setThumbnailActive( + thumbnailId === thumbnailActive ? null : thumbnailId + ) - if (onClickThumbnail) { - // TODO: what is thumbnailId? Should pass display set instead - onClickThumbnail(thumbnailId); + if (onClickThumbnail) { + // TODO: what is thumbnailId? Should pass display set instead + onClickThumbnail(thumbnailId); + } } - }} + } /> )} @@ -90,7 +92,7 @@ const StudyBrowser = ({ tabs, onClickStudy, onClickThumbnail }) => { color="inherit" className="border border-secondary-light rounded-md" > - {tabs.map(tab => { + {tabs.map((tab) => { const { name, label } = tab; const isActive = tabActive === name; return ( @@ -131,7 +133,7 @@ StudyBrowser.propTypes = { studyInstanceUid: PropTypes.string.isRequired, date: PropTypes.string, numInstances: PropTypes.number, - modality: PropTypes.string, + modalities: PropTypes.string, description: PropTypes.string, displaySets: PropTypes.arrayOf( PropTypes.shape({ diff --git a/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx b/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx index 6a8f93205..1e5c18648 100644 --- a/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx +++ b/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx @@ -18,7 +18,88 @@ import { StudyBrowser } from '@ohif/ui'; ## Basic usage - + {() => { + const studyWithSR = { + studyInstanceUid: '1', + date: '07-Sept-2010', + description: 'CHEST/ABD/PELVIS W/CONTRAST', + numInstances: 902, + modalities: 'CT,SR', + displaySets: [ + { + displaySetInstanceUid: 'f69f6asdasd48c-223e-db7f-c4af-b8906641a66e', + description: 'Multiple line image series description lorem sit', + seriesNumber: 1, + numInstances: 68, + componentType: 'thumbnailTracked', + viewportIdentificator: 'A', + isTracked: true, + }, + { + displaySetInstanceUid: 'f69f648c-223e-db7f-c4asdasdaf-b8906641a66e', + description: 'Multiple line image series description lorem sit', + seriesNumber: 1, + numInstances: 68, + componentType: 'thumbnailTracked', + viewportIdentificator: 'B', + }, + { + displaySetInstanceUid: 'f69f648c-223e-dasdasdb7f-c4af-b8906641a66e', + description: 'Multiple line image series description lorem sit', + seriesNumber: 1, + numInstances: 68, + componentType: 'thumbnailTracked', + }, + { + displaySetInstanceUid: 'f69f648c-223e-db7f-c4afas-b8906asd641a66e', + description: 'Multiple line description lorem ipsum dolor sit amet', + modality: 'SR', + componentType: 'thumbnailNoImage', + seriesDate: '07-Sept-2010', + }, + ], + }; + const studySimple = { + studyInstanceUid: '2', + date: '07-Sept-2010', + description: 'CHEST/ABD/PELVIS W/CONTRAST', + numInstances: 902, + modalities: 'CT', + displaySets: [ + { + displaySetInstanceUid: 'f69f648c-223e-db7f-c4af-b8906641a66e', + description: 'Multiple line image series description lorem sit', + seriesNumber: 1, + numInstances: 68, + componentType: 'thumbnailTracked', + }, + ], + }; + const tabs = [ + { + name: 'primary', + label: 'Primary', + studies: [studySimple], + }, + { + name: 'recent', + label: 'Recent', + studies: [studyWithSR, studySimple], + }, + { + name: 'all', + label: 'All', + studies: [studySimple, studyWithSR], + }, + ]; + return ( +
+
+ +
+
+ ); + }}
## Properties diff --git a/platform/ui/src/components/StudyItem/StudyItem.jsx b/platform/ui/src/components/StudyItem/StudyItem.jsx index 9bb0820d6..d2e2cf9a8 100644 --- a/platform/ui/src/components/StudyItem/StudyItem.jsx +++ b/platform/ui/src/components/StudyItem/StudyItem.jsx @@ -8,9 +8,9 @@ const baseClasses = 'first:border-0 border-t border-secondary-light cursor-pointer outline-none'; const StudyItem = ({ - studyDate, - studyDescription, - instances, + date, + description, + numInstances, modalities, trackedSeries, isActive, @@ -29,15 +29,15 @@ const StudyItem = ({ >
-
{studyDate}
+
{date}
- {instances} + {numInstances}
{modalities}
-
{studyDescription}
+
{description}
{!!trackedSeries && ( diff --git a/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx b/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx index 8007ea8fb..06a980c39 100644 --- a/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx +++ b/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Thumbnail, ThumbnailNoImage, ThumbnailTracked } from '@ohif/ui'; -const ThumbnailList = ({ thumbnails }) => { +const ThumbnailList = ({ thumbnails, thumbnailActive, onThumbnailClick }) => { return (
{thumbnails.map( @@ -17,10 +17,11 @@ const ThumbnailList = ({ thumbnails }) => { seriesDate, viewportIdentificator, isTracked, - isActive, imageSrc, imageAltText, }) => { + const isActive = thumbnailActive === displaySetInstanceUid; + switch (componentType) { case 'thumbnail': return ( @@ -33,7 +34,7 @@ const ThumbnailList = ({ thumbnails }) => { imageAltText={imageAltText} viewportIdentificator={viewportIdentificator} isActive={isActive} - onClick={() => {}} + onClick={() => onThumbnailClick(displaySetInstanceUid)} /> ); case 'thumbnailNoImage': @@ -43,7 +44,7 @@ const ThumbnailList = ({ thumbnails }) => { modality={modality} seriesDate={seriesDate} description={description} - onClick={() => {}} + onClick={() => onThumbnailClick(displaySetInstanceUid)} /> ); case 'thumbnailTracked': @@ -58,7 +59,7 @@ const ThumbnailList = ({ thumbnails }) => { viewportIdentificator={viewportIdentificator} isTracked={isTracked} isActive={isActive} - onClick={() => {}} + onClick={() => onThumbnailClick(displaySetInstanceUid)} /> ); default: @@ -87,9 +88,10 @@ ThumbnailList.propTypes = { ]).isRequired, viewportIdentificator: PropTypes.string, isTracked: PropTypes.bool, - isActive: PropTypes.bool, }) ), + thumbnailActive: PropTypes.string, + onThumbnailClick: PropTypes.func, }; export default ThumbnailList; diff --git a/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.jsx b/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.jsx index 20ee0ac63..b0c56f2e3 100644 --- a/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.jsx +++ b/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.jsx @@ -8,18 +8,19 @@ const ThumbnailNoImage = ({ description, seriesDate, modality, onClick }) => {
-
- -
-
+ +
{modality}
{seriesDate}
-
{description}
+
{description}
); diff --git a/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.mdx b/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.mdx index 73b2a1c2e..809cdc3bb 100644 --- a/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.mdx +++ b/platform/ui/src/components/ThumbnailNoImage/ThumbnailNoImage.mdx @@ -21,14 +21,12 @@ import { Thumbnail } from '@ohif/ui';
-
- + alert('Thumbnail was clicked!')} - isActive={false} + onClick={() => alert('ThumbnailNoImage was clicked!')} />
@@ -36,4 +34,4 @@ import { Thumbnail } from '@ohif/ui'; ## Properties - + diff --git a/platform/ui/src/components/contextMenu/ContextMenu.js b/platform/ui/src/components/contextMenu/ContextMenu.js deleted file mode 100644 index 1185a8837..000000000 --- a/platform/ui/src/components/contextMenu/ContextMenu.js +++ /dev/null @@ -1,26 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import './ContextMenu.css'; - -const ContextMenu = ({ items, onClick }) => { - return ( -
e.preventDefault()}> -
    - {items.map((item, index) => ( -
  • - -
  • - ))} -
-
- ); -}; - -ContextMenu.propTypes = { - items: PropTypes.array.isRequired, - onClick: PropTypes.func.isRequired, -}; - -export default ContextMenu; diff --git a/platform/ui/src/components/layoutButton/LayoutChooser.js b/platform/ui/src/components/layoutButton/LayoutChooser.js deleted file mode 100644 index ec993149b..000000000 --- a/platform/ui/src/components/layoutButton/LayoutChooser.js +++ /dev/null @@ -1,129 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import './LayoutChooser.styl'; - -/** - * Adds the 'hover' class to cells above and to the left of the current cell - * This is used to "fill in" the grid that the user will change the layout to, - * if they click on a specific table cell. - **/ - -class LayoutChooser extends PureComponent { - static propTypes = { - Rows: PropTypes.number.isRequired, - Columns: PropTypes.number.isRequired, - visible: PropTypes.bool.isRequired, - selectedCell: PropTypes.object, - boxSize: PropTypes.number.isRequired, - cellBorder: PropTypes.number.isRequired, - onClick: PropTypes.func, - onChange: PropTypes.func, - }; - - static defaultProps = { - Rows: 3, - Columns: 3, - visible: true, - boxSize: 20, - cellBorder: 1, - selectedCell: { - row: -1, - col: -1, - }, - }; - - constructor(props) { - super(props); - this.emptyCell = { - row: -1, - column: -1, - }; - this.state = { - table: [[]], - selectedCell: this.props.selectedCell, - }; - } - componentDidMount() { - this.highlightCells(this.emptyCell); - } - onClick(currentCell) { - this.setState({ - selectedCell: currentCell, - }); - this.highlightCells(currentCell); - if (this.props.onClick) { - this.props.onClick(currentCell); - } - if (this.props.onChange) { - this.props.onChange(currentCell); - } - } - isRange = (cell, parentCell) => { - return cell.row <= parentCell.row && cell.col <= parentCell.col; - }; - highlightCells = currentCell => { - let table = []; - for (let row = 0; row < this.props.Rows; row++) { - let newRow = []; - for (let col = 0; col < this.props.Columns; col++) { - let cell = { row: row, col: col }; - if (this.isRange(cell, currentCell)) { - cell.className = 'hover'; - } else if ( - this.isRange(currentCell, this.emptyCell) && - this.isRange(cell, this.state.selectedCell) - ) { - cell.className = 'selectedBefore'; - } - newRow.push(cell); - } - table.push(newRow); - } - this.setState({ table: table }); - }; - - render() { - let Columns = this.props.Columns; - const style = { - display: this.props.visible ? 'block' : 'none', - minWidth: - Columns * this.props.boxSize + (Columns + 5) * this.props.cellBorder, - }; - return ( -
- - - {this.state.table.map((row, i) => { - return ( - - {row.map((cell, j) => { - return ( - - ); - })} - -
this.highlightCells(cell)} - onMouseLeave={() => this.highlightCells(this.emptyCell)} - onClick={() => this.onClick(cell)} - /> - ); - })} -
-
- ); - } -} - -export { LayoutChooser }; diff --git a/platform/ui/src/components/measurementTable/MeasurementTableItem.styl b/platform/ui/src/components/measurementTable/MeasurementTableItem.styl deleted file mode 100644 index eb3ba7044..000000000 --- a/platform/ui/src/components/measurementTable/MeasurementTableItem.styl +++ /dev/null @@ -1,65 +0,0 @@ -.measurementItem - .rowActions - margin-left: -1px; - background-color: var(--ui-gray-darker) - height: 0 - overflow: hidden - transition: all 0.3s ease - visibility: hidden - padding-left: 14px - - .btnAction - background-color: transparent; - border: none; - color: var(--default-color) - cursor: pointer - line-height: 35px - height: 35px - transition: all 0.3s ease - - &:hover, &:active - color: var(--text-primary-color) - - i - margin-right: 4px; - - &.selected - .rowActions - height: auto; - visibility: visible - - .measurementLocation - margin-top: 9px; - overflow: hidden; - max-width: calc(100% - 50px); - text-overflow: ellipsis; - overflow-wrap: normal; - white-space: nowrap; - - .measurementDisplayText - display: inline-block; - margin-top: 9px; - padding-left: 9px; - width: 90px; - border-left: 1px solid var(--text-secondary-color); - color: var(--text-primary-color); - - .itemIndex - -webkit-box-sizing: initial; - -moz-box-sizing: initial; - box-sizing: initial; - - &.hasWarnings - .itemIndex - opacity: 1 - background-color: #e29e4a; - color: #fff; - - .warning-icon - display: block; - margin: 7px auto 0; - - svg - width: 22px; - height: 20px; - pointer-events: inherit; diff --git a/platform/ui/src/components/quickSwitch/QuickSwitch.js b/platform/ui/src/components/quickSwitch/QuickSwitch.js deleted file mode 100644 index 8f870c06a..000000000 --- a/platform/ui/src/components/quickSwitch/QuickSwitch.js +++ /dev/null @@ -1,151 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -import { StudiesList } from './StudiesList.js'; -import { ScrollableArea } from './../../ScrollableArea/ScrollableArea.js'; -import { SeriesList } from './SeriesList.js'; - -import './QuickSwitch.styl'; - -export class QuickSwitch extends Component { - static propTypes = { - side: PropTypes.string, - studyListData: PropTypes.array.isRequired, - onSeriesSelected: PropTypes.func.isRequired, - seriesData: PropTypes.array, - onStudySelected: PropTypes.func, - activeStudyInstanceUID: PropTypes.string, - activeDisplaySetInstanceUID: PropTypes.string, - }; - - constructor(props) { - super(props); - - this.state = { - seriesQuickSwitchOpen: false, - sideClass: this.props.side || '', - activeStudyInstanceUID: this.props.activeStudyInstanceUID, - activeDisplaySetInstanceUID: this.props.activeDisplaySetInstanceUID, - }; - } - - componentDidUpdate(prevProps) { - const props = this.props; - - if (props.activeStudyInstanceUID !== prevProps.activeStudyInstanceUID) { - this.setState({ - activeStudyInstanceUID: props.activeStudyInstanceUID, - }); - } - - if ( - props.activeDisplaySetInstanceUID !== - prevProps.activeDisplaySetInstanceUID - ) { - this.setState({ - activeDisplaySetInstanceUID: props.activeDisplaySetInstanceUID, - }); - } - } - - render() { - const quickSwitchClass = this.state.seriesQuickSwitchOpen - ? 'series-triggered' - : ''; - - return ( -
-
-
Series
-
- {this.getSmallListItems()} - - - -
-
-
-
Study
-
- - - -
-
-
- ); - } - - getSeriesItems = () => { - let seriesData; - - if (this.props.seriesData) { - seriesData = this.props.seriesData; - } else if (this.state.activeStudyInstanceUID) { - const study = this.props.studyListData.find( - study => study.StudyInstanceUID === this.state.activeStudyInstanceUID - ); - - seriesData = study.thumbnails; - } else { - seriesData = this.props.studyListData[0].thumbnails; - } - - return seriesData || []; - }; - - getSmallListItems = () => { - const seriesItems = this.getSeriesItems() || []; - return seriesItems.map((seriesData, index) => { - const active = - seriesData.displaySetInstanceUID === - this.state.activeDisplaySetInstanceUID; - return ( -
- ); - }); - }; - - onStudyClick = studyDataSelected => { - if (this.props.onStudySelected) { - this.props.onStudySelected(studyDataSelected); - } - this.setState({ - activeStudyInstanceUID: studyDataSelected.StudyInstanceUID, - seriesQuickSwitchOpen: true, - }); - }; - - onSeriesClick = seriesDataSelected => { - this.setState({ - activeDisplaySetInstanceUID: seriesDataSelected.displaySetInstanceUID, - }); - - this.props.onSeriesSelected(seriesDataSelected); - }; - - showSeriesSwitch = () => { - this.setState({ - seriesQuickSwitchOpen: true, - }); - }; - - hideSeriesSwitch = () => { - this.setState({ - seriesQuickSwitchOpen: false, - }); - }; -} diff --git a/platform/ui/src/components/quickSwitch/SeriesList.js b/platform/ui/src/components/quickSwitch/SeriesList.js deleted file mode 100644 index ad0c62c76..000000000 --- a/platform/ui/src/components/quickSwitch/SeriesList.js +++ /dev/null @@ -1,40 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -import { Thumbnail } from './../studyBrowser'; -import './SeriesList.styl'; - -export class SeriesList extends Component { - static propTypes = { - seriesItems: PropTypes.array.isRequired, - onClick: PropTypes.func.isRequired, - activeDisplaySetInstanceUID: PropTypes.string, - }; - - render() { - return ( - -
-
{this.getSeriesItems()}
-
-
- ); - } - - getSeriesItems = () => { - return this.props.seriesItems.map((seriesData, index) => { - return ( - this.props.onClick(seriesData)} - /> - ); - }); - }; -} diff --git a/platform/ui/src/components/quickSwitch/StudiesItem.js b/platform/ui/src/components/quickSwitch/StudiesItem.js deleted file mode 100644 index ff3d8d2bb..000000000 --- a/platform/ui/src/components/quickSwitch/StudiesItem.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -import './StudiesItem.styl'; - -export class StudiesItem extends Component { - static propTypes = { - onClick: PropTypes.func.isRequired, - studyData: PropTypes.object.isRequired, - active: PropTypes.bool, - }; - - render() { - const { - StudyDate, - StudyDescription, - modalities, - studyAvailable, - } = this.props.studyData; - const activeClass = this.props.active ? ' active' : ''; - const hasDescriptionAndDate = StudyDate && StudyDescription; - return ( -
-
-
-
- {modalities} -
-
-
- {hasDescriptionAndDate ? ( - -
{StudyDate}
-
{StudyDescription}
-
- ) : ( -
- {studyAvailable ? ( - N/A - ) : ( - Click to load - )} -
- )} -
-
-
- ); - } - - getModalitiesStyle = () => { - return {}; - }; -} diff --git a/platform/ui/src/components/quickSwitch/StudiesItem.styl b/platform/ui/src/components/quickSwitch/StudiesItem.styl deleted file mode 100644 index 4302ce1f1..000000000 --- a/platform/ui/src/components/quickSwitch/StudiesItem.styl +++ /dev/null @@ -1,133 +0,0 @@ -$boxHoverBackgroundColor = #14191E -$boxHoverBorderColor = #2d4660 -$boxActiveBorderColor = #131D29 -$boxWidth = 50px -$borderThickness = 2px -$boxBorderRadius = 8px -$nestingMargin = 6px -$spacerX = 7px -$spacerY = 12px - -.studyBrowseItem - margin-bottom: 10px; - position: relative - // required transformation to make inner fixed elements relative to this one - transform: scale(1) - - &.active - .studyItemBox - border-color: var(--active-color) - - .studyModality - color: var(--primary-background-color) - & - &:before - &:after - background-color: var(--active-color) - border-color: $boxActiveBorderColor - - &:not(.active) .studyBrowserSeries - max-height: 0 !important - - .studySeriesContainer - opacity: 0 - transform: translateY(-100%) - - .studyBrowserSeries - overflow: hidden - transition: max-height 0.3s ease - - .studySeriesContainer - opacity: 1 - transition: opacity 0.3s ease, transform 0.3s ease - transform: translateY(0) - transform-origin: 50% 0% - -.studyItemBox - border: 3px solid var(--ui-border-color-dark) - border-radius: 12px - cursor: pointer - padding: $spacerY $spacerX ($spacerY - 1) - position: relative - transition: $sidebarTransition - background-color: $boxHoverBackgroundColor - z-index: 0 - - &:hover - border-color: var(--active-color) - - &.additional - color: var(--text-secondary-color) - - .studyModality - color: var(--primary-background-color) - & - &:before - &:after - background-color: var(--active-color) - - &.additional - color: var(--text-primary-color) - font-size: 16px - font-weight: normal - height: 91px - line-height: 91px - padding: 0 - text-align: center - - .studyText - font-size: 13px - left: ($spacerX * 3) + $boxWidth + ($nestingMargin * 3) - line-height: 14px - position: absolute - right: $spacerX - top: $spacerY - .studyDate - margin-top: 8px - color: var(--text-secondary-color) - .studyDescription - margin-top: 8px - color: var(--text-primary-color) - .studyAvailability - margin-top: 24px - color: var(--text-primary-color) - - .studyModality - color: var(--text-secondary-color) - font-size: 20px - line-height: $boxWidth - margin-left: $nestingMargin * 2 - margin-top: $nestingMargin * 2 - position: relative - - .studyModalityText - height: 100% - overflow: hidden - text-align: center - text-transform: uppercase - - & - &:before - &:after - border: $borderThickness solid var(--primary-background-color) - background-color: var(--box-background-color) - border-radius: $boxBorderRadius - height: $boxWidth + ($borderThickness * 2) - transition($sidebarTransition) - width: $boxWidth + ($borderThickness * 2) - - &:before - &:after - display: block - content: '' - position: absolute - - &:before - top: -($borderThickness + $nestingMargin) - left: -($borderThickness + $nestingMargin) - z-index: -1 - - &:after - top: -($borderThickness + ($nestingMargin * 2)) - left: -($borderThickness + ($nestingMargin * 2)) - z-index: -2 diff --git a/platform/ui/src/components/quickSwitch/StudiesList.js b/platform/ui/src/components/quickSwitch/StudiesList.js deleted file mode 100644 index 15053557b..000000000 --- a/platform/ui/src/components/quickSwitch/StudiesList.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -import { StudiesItem } from './StudiesItem.js'; -import './StudiesList.styl'; - -export class StudiesList extends Component { - static propTypes = { - class: PropTypes.string, - studyListData: PropTypes.array.isRequired, - onClick: PropTypes.func.isRequired, - activeStudyInstanceUID: PropTypes.string, - }; - - render() { - return ( -
- {this.getBrowserItems()} -
- ); - } - - getBrowserItems = () => { - return this.props.studyListData.map((studyData, index) => { - return ( - this.props.onClick(studyData)} - /> - ); - }); - }; -} diff --git a/platform/ui/src/components/quickSwitch/__docs__/quickSwitch.mdx b/platform/ui/src/components/quickSwitch/__docs__/quickSwitch.mdx deleted file mode 100644 index 75b228448..000000000 --- a/platform/ui/src/components/quickSwitch/__docs__/quickSwitch.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -name: Quick Switch -menu: Components -route: /components/quick-switch ---- - -import { Playground, Props } from 'docz' -import { State } from 'react-powerplug' -import { QuickSwitch } from './../index.js' -// -import studies from './studies.js' - -# Quick Switch - -## Basic usage - - - - {({ state, setState }) => ( - { - return !!study.active; - }).thumbnails} - onSeriesSelected={(selectedSeries) => { - const { studyListData } = state; - const selectedId = selectedSeries.displaySetInstanceUID; - - studyListData.forEach(study => { - study.thumbnails.forEach(series => { - series.active = series.displaySetInstanceUID === selectedId; - }) - }); - - setState({ studyListData }); - }} - onStudySelected={(selectedStudy) => { - const { studyListData } = state; - const selectedId = selectedStudy.StudyInstanceUID; - - studyListData.forEach(study => { - study.active = study.StudyInstanceUID === selectedId; - }); - - setState({ studyListData }); - }} - /> - )} - - - - - -## API - - diff --git a/platform/ui/src/components/quickSwitch/__docs__/studies.js b/platform/ui/src/components/quickSwitch/__docs__/studies.js deleted file mode 100644 index 2580fda90..000000000 --- a/platform/ui/src/components/quickSwitch/__docs__/studies.js +++ /dev/null @@ -1,76 +0,0 @@ -export default [ - { - StudyInstanceUID: '10001', - StudyDescription: 'Anti-PD-1', - modalities: 'CT', - StudyDate: '18-nov-2018', - active: false, - thumbnails: [ - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/Anti-PD-1_Lung.jpg', - SeriesDescription: 'Anti-PD-1_Lung', - SeriesNumber: '2', - numImageFrames: 512, - displaySetInstanceUID: '10001-1', - stackPercentComplete: 30, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/Anti-PD-1_MELANOMA.jpg', - SeriesDescription: 'Anti-PD-1_MELANOMA', - SeriesNumber: '2', - InstanceNumber: '1', - numImageFrames: 256, - displaySetInstanceUID: '10001-2', - stackPercentComplete: 70, - }, - ], - }, - { - StudyInstanceUID: '10002', - StudyDescription: 'CPTAC', - modalities: 'CT', - StudyDate: '16-aug-2017', - active: true, - thumbnails: [ - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-GBM.jpg', - SeriesDescription: 'CPTAC-GBM', - active: true, - SeriesNumber: '2', - numImageFrames: 512, - displaySetInstanceUID: '10002-1', - stackPercentComplete: 100, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-CM.jpg', - SeriesDescription: 'CPTAC-CM', - SeriesNumber: '2', - InstanceNumber: '1', - displaySetInstanceUID: '10002-2', - numImageFrames: 256, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-HNSCC.jpg', - SeriesDescription: 'CPTAC-HNSCC', - SeriesNumber: '2', - InstanceNumber: '1', - displaySetInstanceUID: '10002-3', - numImageFrames: 256, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-LSCC.jpg', - SeriesDescription: 'CPTAC-LSCC', - SeriesNumber: '2', - InstanceNumber: '1', - displaySetInstanceUID: '10002-4', - numImageFrames: 256, - }, - ], - }, -]; diff --git a/platform/ui/src/components/roundedButtonGroup/RoundedButtonGroup.css b/platform/ui/src/components/roundedButtonGroup/RoundedButtonGroup.css deleted file mode 100644 index 3bf03e5e0..000000000 --- a/platform/ui/src/components/roundedButtonGroup/RoundedButtonGroup.css +++ /dev/null @@ -1,84 +0,0 @@ -.RoundedButtonGroup { - --height: 25px; - position: relative; - z-index: 0; -} - -.roundedButtonWrapper { - cursor: pointer; - display: inline-block; - float: left; - margin-left: -2px; - text-decoration: none; - text-align: center; -} - -.roundedButtonWrapper.disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.RoundedButtonGroup .roundedButtonWrapper .roundedButton { - align-items: center; - background-color: var(--ui-gray-dark); - border: 2px solid var(--ui-border-color-dark); - color: var(--text-secondary-color); - display: flex; - font-size: 15px; - font-weight: 500; - justify-content: center; - height: var(--height); - line-height: var(--height); - padding: 0 22px; - position: relative; - text-transform: uppercase; - transition: var(--sidebar-transition); - z-index: 1; -} - -.roundedButtonWrapper .roundedButton svg .roundedButtonWrapper .roundedButton span { - margin: 0 2px; -} - -.roundedButtonWrapper .roundedButton i { - line-height: 15px; - font-size: 15px; -} - -.roundedButtonWrapper .bottomLabel { - padding: 0 10px 0 10px; -} - -.bottomLabel { - color: var(--text-secondary-color); - font-size: 12px; - font-weight: 500; - line-height: 12px; - margin-top: 8px; -} - -.roundedButtonWrapper:first-child { - margin-left: 0; -} - -.RoundedButtonGroup .roundedButtonWrapper:first-child .roundedButton { - border-bottom-left-radius: var(--height); - border-top-left-radius: var(--height); -} - -.RoundedButtonGroup .roundedButtonWrapper:last-child .roundedButton { - border-bottom-right-radius: var(--height); - border-top-right-radius: var(--height); -} - -.roundedButtonWrapper:hover .roundedButton { - background-color: var(--box-background-color); - color: var(--ui-gray-dark); -} - -.roundedButtonWrapper.active .roundedButton { - background-color: var(--active-color); - border-color: var(--ui-border-color-active); - color: var(--ui-gray-dark); - z-index: 2; -} diff --git a/platform/ui/src/components/snackbar/Snackbar.css b/platform/ui/src/components/snackbar/Snackbar.css deleted file mode 100644 index bb99cefe6..000000000 --- a/platform/ui/src/components/snackbar/Snackbar.css +++ /dev/null @@ -1,196 +0,0 @@ -.sb-container { - position: fixed; - width: var(--snackbar-size); - padding: 20px; - z-index: var(--snackbar-zIndex); - box-sizing: border-box; - height: auto; -} - -.sb-topLeft { - top: 0; - bottom: auto; - left: 0; - right: auto; -} - -.sb-topCenter { - left: 50%; - top: 0; - bottom: auto; - transform: translateX(-50%); -} - -.sb-topRight { - top: 0; - bottom: auto; - left: auto; - right: 0; -} - -.sb-bottomLeft { - top: auto; - bottom: 0px; - left: 0px; - right: auto; -} - -.sb-bottomCenter { - left: 50%; - bottom: 0; - top: auto; - transform: translateX(-50%); -} - -.sb-bottomRight { - top: auto; - bottom: 0px; - left: auto; - right: 0px; - margin: 10px 0 0; -} - -.sb-topLeft .sb-item, -.sb-topCenter .sb-item, -.sb-topRight .sb-item { - margin: 10px 0 0; -} - -.sb-bottomLeft .sb-item, -.sb-bottomCenter .sb-item, -.sb-bottomRight .sb-item { - margin: 0 0 10px; -} - -.sb-closeBtn { - height: 20px; - opacity: 1; - overflow: hidden; - padding: 2px; - text-align: center; - text-shadow: none; - width: 20px; - cursor: pointer; - position: absolute; - right: 5px; - top: 5px; - transition: all 0.3s ease; - background: rgba(255, 255, 255, 0.6); - border-radius: 100%; -} - -.sb-closeBtn:hover { - background: #fff; -} - -.sb-closeIcon { - display: block; - font-size: 0; - height: 100%; - line-height: 0; - overflow: hidden; - position: relative; - width: 100%; -} - -.sb-closeIcon:after, -.sb-closeIcon:before { - content: ' '; - display: block; - height: 2px; - transition: all 0.3s ease; - width: 12px; - background-color: #222; - opacity: 1; - position: absolute; -} - -.sb-closeIcon:before { - left: 4px; - top: 3px; - - transform: rotate(45deg); - transform-origin: 0px 50%; -} - -.sb-closeIcon:after { - right: 3px; - top: 5px; - transform: rotate(-45deg); - transform-origin: calc(100% - 3px) 50%; -} - -.sb-title { - font-size: 16px; - font-weight: bold; -} - -.sb-message { - font-size: 14px; - word-break: normal; -} - -.sb-item { - position: relative; - transition: height 300ms ease; - animation: fadein 1s; - padding: 20px; - color: white; - overflow: hidden; - border-radius: 4px; - box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.2), 0 1px 18px 0 rgba(0, 0, 0, 0.12), - 0 3px 5px -1px rgba(0, 0, 0, 0.14); -} - -.sb-item a { - color: white; - text-decoration: underline; -} - -.sb-container .sb-hidden { - padding-top: 0; - padding-bottom: 0; - margin-bottom: 0; - height: 0; - opacity: 0; - transition: all 300ms ease; -} - -.sb-success { - background-color: var(--snackbar-success); -} - -.sb-error { - background-color: var(--snackbar-error); -} - -.sb-warning { - background-color: var(--snackbar-warning); -} - -.sb-info { - background-color: var(--snackbar-info); -} - -@keyframes fadein { - from { - opacity: 0; - top: 30px; - } - to { - opacity: 1; - top: 0; - } -} - -/* Internet Explorer */ -@-ms-keyframes fadein { - from { - opacity: 0; - top: 30px; - } - to { - opacity: 1; - top: 0; - } -} diff --git a/platform/ui/src/components/studyBrowser/ImageThumbnail.js b/platform/ui/src/components/studyBrowser/ImageThumbnail.js deleted file mode 100644 index 98891f279..000000000 --- a/platform/ui/src/components/studyBrowser/ImageThumbnail.js +++ /dev/null @@ -1,144 +0,0 @@ -/* global cornerstone */ -import './ImageThumbnail.styl'; - -import { utils } from '@ohif/core'; -import React, { useState, useEffect, createRef } from 'react'; - -import PropTypes from 'prop-types'; -import ViewportErrorIndicator from '../../viewer/ViewportErrorIndicator'; -import ViewportLoadingIndicator from '../../viewer/ViewportLoadingIndicator'; - -// TODO: How should we have this component depend on Cornerstone? -// - Passed in as a prop? -// - Set as external dependency? -// - Pass in the entire load and render function as a prop? -//import cornerstone from 'cornerstone-core'; -function ImageThumbnail(props) { - const { - width, - height, - imageSrc, - imageId, - stackPercentComplete, - error: propsError, - } = props; - - const [isLoading, setLoading] = useState(false); - const [error, setError] = useState(false); - const [image, setImage] = useState({}); - const canvasRef = createRef(); - - let loadingOrError; - let cancelablePromise; - - if (propsError || error) { - loadingOrError = ; - } else if (isLoading) { - loadingOrError = ; - } - - const showStackLoadingProgressBar = stackPercentComplete !== undefined; - - const shouldRenderToCanvas = () => { - return imageId && !imageSrc; - }; - - const fetchImagePromise = () => { - if (!cancelablePromise) { - return; - } - - setLoading(true); - cancelablePromise - .then(response => { - setImage(response); - }) - .catch(error => { - if (error.isCanceled) return; - setLoading(false); - setError(true); - throw new Error(error); - }); - }; - - const setImagePromise = () => { - if (shouldRenderToCanvas()) { - cancelablePromise = utils.makeCancelable( - cornerstone.loadAndCacheImage(imageId) - ); - } - }; - - const purgeCancelablePromise = () => { - if (cancelablePromise) { - cancelablePromise.cancel(); - } - }; - - useEffect(() => { - return () => { - purgeCancelablePromise(); - }; - }, [purgeCancelablePromise]); - - useEffect(() => { - if (image.imageId) { - cornerstone.renderToCanvas(canvasRef.current, image); - setLoading(false); - } - }, [canvasRef, image, image.imageId]); - - useEffect(() => { - if (!image.imageId || image.imageId !== imageId) { - purgeCancelablePromise(); - setImagePromise(); - fetchImagePromise(); - } - }, [fetchImagePromise, image.imageId, imageId, purgeCancelablePromise, setImagePromise]); - - return ( -
-
- {shouldRenderToCanvas() ? ( - - ) : ( - {''} - )} -
- {loadingOrError} - {showStackLoadingProgressBar && ( -
-
-
- )} - {isLoading &&
} -
- ); -} - -ImageThumbnail.propTypes = { - imageSrc: PropTypes.string, - imageId: PropTypes.string, - error: PropTypes.bool, - width: PropTypes.number, - height: PropTypes.number, - stackPercentComplete: PropTypes.number.isRequired, -}; - -ImageThumbnail.defaultProps = { - error: false, - stackPercentComplete: 0, - width: 217, - height: 123, -}; - -export default ImageThumbnail; diff --git a/platform/ui/src/components/studyBrowser/StudyBrowser.js b/platform/ui/src/components/studyBrowser/StudyBrowser.js deleted file mode 100644 index 921888807..000000000 --- a/platform/ui/src/components/studyBrowser/StudyBrowser.js +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Thumbnail } from './Thumbnail.js'; -import './StudyBrowser.styl'; - -function StudyBrowser(props) { - const { - studies, - onThumbnailClick, - onThumbnailDoubleClick, - supportsDrag, - } = props; - - return ( -
-
- {studies - .map((study, studyIndex) => { - const { StudyInstanceUID } = study; - return study.thumbnails.map((thumb, thumbIndex) => { - // TODO: Thumb has more props than we care about? - const { - altImageText, - displaySetInstanceUID, - imageId, - InstanceNumber, - numImageFrames, - SeriesDescription, - SeriesNumber, - stackPercentComplete, - } = thumb; - - return ( -
- -
- ); - }); - }) - .flat()} -
-
- ); -} - -const noop = () => {}; - -StudyBrowser.propTypes = { - studies: PropTypes.arrayOf( - PropTypes.shape({ - StudyInstanceUID: PropTypes.string.isRequired, - thumbnails: PropTypes.arrayOf( - PropTypes.shape({ - altImageText: PropTypes.string, - displaySetInstanceUID: PropTypes.string.isRequired, - imageId: PropTypes.string, - InstanceNumber: PropTypes.number, - numImageFrames: PropTypes.number, - SeriesDescription: PropTypes.string, - SeriesNumber: PropTypes.number, - stackPercentComplete: PropTypes.number, - }) - ), - }) - ).isRequired, - supportsDrag: PropTypes.bool, - onThumbnailClick: PropTypes.func, - onThumbnailDoubleClick: PropTypes.func, -}; - -StudyBrowser.defaultProps = { - studies: [], - supportsDrag: true, - onThumbnailClick: noop, - onThumbnailDoubleClick: noop, -}; - -export { StudyBrowser }; diff --git a/platform/ui/src/components/studyBrowser/Thumbnail.js b/platform/ui/src/components/studyBrowser/Thumbnail.js deleted file mode 100644 index 66b102560..000000000 --- a/platform/ui/src/components/studyBrowser/Thumbnail.js +++ /dev/null @@ -1,152 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { useDrag } from 'react-dnd'; -import ImageThumbnail from './ImageThumbnail'; -import classNames from 'classnames'; - -import './Thumbnail.styl'; - -function ThumbnailFooter({ - SeriesDescription, - SeriesNumber, - InstanceNumber, - numImageFrames, -}) { - const infoOnly = !SeriesDescription; - - const getInfo = (value, icon, className = '') => { - return ( -
-
{icon}
-
{value}
-
- ); - }; - const getSeriesInformation = ( - SeriesNumber, - InstanceNumber, - numImageFrames - ) => { - if (!SeriesNumber && !InstanceNumber && !numImageFrames) { - return; - } - - return ( -
- {getInfo(SeriesNumber, 'S:')} - {getInfo(InstanceNumber, 'I:')} - {getInfo(numImageFrames, '', 'image-frames')} -
- ); - }; - - return ( -
-
{SeriesDescription}
- {getSeriesInformation(SeriesNumber, InstanceNumber, numImageFrames)} -
- ); -} - -function Thumbnail(props) { - const { - active, - altImageText, - error, - displaySetInstanceUID, - imageId, - imageSrc, - InstanceNumber, - numImageFrames, - SeriesDescription, - SeriesNumber, - stackPercentComplete, - StudyInstanceUID, - onClick, - onDoubleClick, - onMouseDown, - supportsDrag, - } = props; - - const [collectedProps, drag, dragPreview] = useDrag({ - // `droppedItem` in `dropTarget` - // The only data it will have access to - item: { - StudyInstanceUID, - displaySetInstanceUID, - type: 'thumbnail', // Has to match `dropTarget`'s type - }, - canDrag: function(monitor) { - return supportsDrag; - }, - }); - - const hasImage = imageSrc || imageId; - const hasAltText = altImageText !== undefined; - - return ( -
- {/* SHOW IMAGE */} - {hasImage && ( - - )} - {/* SHOW TEXT ALTERNATIVE */} - {!hasImage && hasAltText && ( -
-

{altImageText}

-
- )} - {ThumbnailFooter(props)} -
- ); -} - -const noop = () => {}; - -Thumbnail.propTypes = { - supportsDrag: PropTypes.bool, - id: PropTypes.string.isRequired, - displaySetInstanceUID: PropTypes.string.isRequired, - StudyInstanceUID: PropTypes.string.isRequired, - imageSrc: PropTypes.string, - imageId: PropTypes.string, - error: PropTypes.bool, - active: PropTypes.bool, - stackPercentComplete: PropTypes.number, - /** - altImageText will be used when no imageId or imageSrc is provided. -It will be displayed inside the
. This is useful when it is difficult - to make a preview for a type of DICOM series (e.g. DICOM-SR) - */ - altImageText: PropTypes.string, - SeriesDescription: PropTypes.string, - SeriesNumber: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - InstanceNumber: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - numImageFrames: PropTypes.number, - onDoubleClick: PropTypes.func, - onClick: PropTypes.func, - onMouseDown: PropTypes.func, -}; - -Thumbnail.defaultProps = { - supportsDrag: false, - active: false, - error: false, - stackPercentComplete: 0, - onDoubleClick: noop, - onClick: noop, - onMouseDown: noop, -}; - -export { Thumbnail }; diff --git a/platform/ui/src/components/studyBrowser/__docs__/ExampleDropTarget.js b/platform/ui/src/components/studyBrowser/__docs__/ExampleDropTarget.js deleted file mode 100644 index e505eac31..000000000 --- a/platform/ui/src/components/studyBrowser/__docs__/ExampleDropTarget.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { Component } from 'react'; -import { DropTarget } from 'react-dnd'; -import PropTypes from 'prop-types'; -import './ExampleDropTarget.css'; - -// Drag sources and drop targets only interact -// if they have the same string type. -const Types = { - THUMBNAIL: 'thumbnail', -}; - -const divTarget = { - drop(props, monitor, component) { - // Note: For this example we use setState, but in - // OHIF we will update the redux store instead - const item = monitor.getItem(); - - component.setState({ - item: { - id: item.id, - SeriesDescription: item.SeriesDescription, - }, - }); - return { id: 'ExampleDropTarget' }; - }, -}; - -// TODO: Find out why we can't move this into the Example app instead. -// It looks like the context isn't properly shared. -class CustomDropTarget extends Component { - static className = 'ExampleDropTarget'; - - state = { - item: null, - }; - - static defaultProps = { - isOver: false, - }; - - static propTypes = { - connectDropTarget: PropTypes.func.isRequired, - canDrop: PropTypes.bool.isRequired, - isOver: PropTypes.bool.isRequired, - }; - - render() { - const { canDrop, isOver, connectDropTarget } = this.props; - const isActive = canDrop && isOver; - - let className = ExampleDropTarget.className; - - if (isActive) { - className += ' hovered'; - } else if (canDrop) { - className += ' can-drop'; - } - - return connectDropTarget( -
-

- {isActive - ? 'Release to drop' - : 'Drag / Drop something from the Study Browser here'} -

-

- {this.state.item && JSON.stringify(this.state.item)} -

-
- ); - } -} - -const collect = (connect, monitor) => ({ - connectDropTarget: connect.dropTarget(), - isOver: monitor.isOver(), - canDrop: monitor.canDrop(), -}); - -const ExampleDropTarget = DropTarget(Types.THUMBNAIL, divTarget, collect)( - CustomDropTarget -); - -export { ExampleDropTarget }; diff --git a/platform/ui/src/components/studyBrowser/__docs__/exampleStudies.js b/platform/ui/src/components/studyBrowser/__docs__/exampleStudies.js deleted file mode 100644 index a9ca38c67..000000000 --- a/platform/ui/src/components/studyBrowser/__docs__/exampleStudies.js +++ /dev/null @@ -1,75 +0,0 @@ -export const studies = [ - { - thumbnails: [ - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/Anti-PD-1_Lung.jpg', - SeriesDescription: 'Anti-PD-1_Lung', - active: true, - SeriesNumber: '2', - numImageFrames: 512, - stackPercentComplete: 30, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/Anti-PD-1_MELANOMA.jpg', - SeriesDescription: 'Anti-PD-1_MELANOMA', - SeriesNumber: '2', - InstanceNumber: '1', - numImageFrames: 256, - stackPercentComplete: 70, - }, - { - altImageText: 'SR', - SeriesDescription: 'Imaging Measurement Report', - SeriesNumber: '3', - stackPercentComplete: 100, - }, - ], - }, - { - thumbnails: [ - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-GBM.jpg', - SeriesDescription: 'CPTAC-GBM', - active: true, - SeriesNumber: '2', - numImageFrames: 512, - stackPercentComplete: 100, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-CM.jpg', - SeriesDescription: 'CPTAC-CM', - SeriesNumber: '2', - InstanceNumber: '1', - numImageFrames: 256, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-HNSCC.jpg', - SeriesDescription: 'CPTAC-HNSCC', - SeriesNumber: '2', - InstanceNumber: '1', - numImageFrames: 256, - }, - { - imageSrc: - 'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-LSCC.jpg', - SeriesDescription: 'CPTAC-LSCC', - SeriesNumber: '2', - InstanceNumber: '1', - numImageFrames: 256, - }, - ], - }, -]; - -export function onThumbnailClick() { - console.warn('onThumbnailClick'); -} - -export function onThumbnailDoubleClick() { - console.warn('onThumbnailDoubleClick'); -} diff --git a/platform/ui/src/components/studyList/StudyList.js b/platform/ui/src/components/studyList/StudyList.js deleted file mode 100644 index c8fb7415d..000000000 --- a/platform/ui/src/components/studyList/StudyList.js +++ /dev/null @@ -1,409 +0,0 @@ -import './StudyList.styl'; - -import React from 'react'; -import classNames from 'classnames'; -import TableSearchFilter from './TableSearchFilter.js'; -import PropTypes from 'prop-types'; -import { StudyListLoadingText } from './StudyListLoadingText.js'; -import { useTranslation } from 'react-i18next'; - -const getContentFromUseMediaValue = ( - displaySize, - contentArrayMap, - defaultContent -) => { - const content = - displaySize in contentArrayMap - ? contentArrayMap[displaySize] - : defaultContent; - - return content; -}; -/** - * - * - * @param {*} props - * @returns - */ -function StudyList(props) { - const { - isLoading, - hasError, - studies, - sort, - onSort: handleSort, - filterValues, - onFilterChange: handleFilterChange, - onSelectItem: handleSelectItem, - studyListDateFilterNumDays, - displaySize, - } = props; - const { t, ready: translationsAreReady } = useTranslation('StudyList'); - - const largeTableMeta = [ - { - displayText: t('PatientName'), - fieldName: 'PatientName', - inputType: 'text', - size: 330, - }, - { - displayText: t('MRN'), - fieldName: 'PatientID', - inputType: 'text', - size: 378, - }, - { - displayText: t('AccessionNumber'), - fieldName: 'AccessionNumber', - inputType: 'text', - size: 180, - }, - { - displayText: t('StudyDate'), - fieldName: 'StudyDate', - inputType: 'date-range', - size: 300, - }, - { - displayText: t('Modality'), - fieldName: 'modalities', - inputType: 'text', - size: 114, - }, - { - displayText: t('StudyDescription'), - fieldName: 'StudyDescription', - inputType: 'text', - size: 335, - }, - ]; - - const mediumTableMeta = [ - { - displayText: `${t('PatientName')} / ${t('MRN')}`, - fieldName: 'patientNameOrId', - inputType: 'text', - size: 250, - }, - { - displayText: t('Description'), - fieldName: 'accessionOrModalityOrDescription', - inputType: 'text', - size: 350, - }, - { - displayText: t('StudyDate'), - fieldName: 'StudyDate', - inputType: 'date-range', - size: 300, - }, - ]; - - const smallTableMeta = [ - { - displayText: t('Search'), - fieldName: 'allFields', - inputType: 'text', - size: 100, - }, - ]; - - const tableMeta = getContentFromUseMediaValue( - displaySize, - { large: largeTableMeta, medium: mediumTableMeta, small: smallTableMeta }, - smallTableMeta - ); - - const totalSize = tableMeta - .map(field => field.size) - .reduce((prev, next) => prev + next); - - return translationsAreReady ? ( - - - {tableMeta.map((field, i) => { - const size = field.size; - const percentWidth = (size / totalSize) * 100.0; - - return ; - })} - - - - - - - - {/* I'm not in love with this approach, but it's the quickest way for now - * - * - Display different content based on loading, empty, results state - * - * This is not ideal because it create a jump in focus. For loading especially, - * We should keep our current results visible while we load the new ones. - */} - {/* LOADING */} - {isLoading && ( - - - - )} - {!isLoading && hasError && ( - - - - )} - {/* EMPTY */} - {!isLoading && !studies.length && ( - - - - )} - {!isLoading && - studies.map((study, index) => ( - handleSelectItem(StudyInstanceUID)} - AccessionNumber={study.AccessionNumber || ''} - modalities={study.modalities} - PatientID={study.PatientID || ''} - PatientName={study.PatientName || ''} - StudyDate={study.StudyDate} - StudyDescription={study.StudyDescription || ''} - StudyInstanceUID={study.StudyInstanceUID} - displaySize={displaySize} - /> - ))} - -
- -
-
- {t('There was an error fetching studies')} -
-
-
{t('No matching results')}
-
- ) : null; -} - -StudyList.propTypes = { - isLoading: PropTypes.bool.isRequired, - hasError: PropTypes.bool.isRequired, - studies: PropTypes.array.isRequired, - onSelectItem: PropTypes.func.isRequired, - // ~~ SORT - sort: PropTypes.shape({ - fieldName: PropTypes.string, - direction: PropTypes.oneOf(['desc', 'asc', null]), - }).isRequired, - onSort: PropTypes.func.isRequired, - // ~~ FILTERS - filterValues: PropTypes.shape({ - PatientName: PropTypes.string.isRequired, - PatientID: PropTypes.string.isRequired, - AccessionNumber: PropTypes.string.isRequired, - StudyDate: PropTypes.string.isRequired, - modalities: PropTypes.string.isRequired, - StudyDescription: PropTypes.string.isRequired, - patientNameOrId: PropTypes.string.isRequired, - accessionOrModalityOrDescription: PropTypes.string.isRequired, - allFields: PropTypes.string.isRequired, - studyDateTo: PropTypes.any, - studyDateFrom: PropTypes.any, - }).isRequired, - onFilterChange: PropTypes.func.isRequired, - studyListDateFilterNumDays: PropTypes.number, - displaySize: PropTypes.string, -}; - -StudyList.defaultProps = {}; - -function TableRow(props) { - const { - AccessionNumber, - isHighlighted, - modalities, - PatientID, - PatientName, - StudyDate, - StudyDescription, - StudyInstanceUID, - onClick: handleClick, - displaySize, - } = props; - - const { t } = useTranslation('StudyList'); - - const largeRowTemplate = ( - handleClick(StudyInstanceUID)} - className={classNames({ active: isHighlighted })} - > - - {PatientName || `(${t('Empty')})`} - - {PatientID} - {AccessionNumber} - {StudyDate} - - {modalities || `(${t('Empty')})`} - - {StudyDescription} - - ); - - const mediumRowTemplate = ( - handleClick(StudyInstanceUID)} - className={classNames({ active: isHighlighted })} - > - - {PatientName || `(${t('Empty')})`} -
{PatientID}
- - -
- {/* DESCRIPTION */} -
- {StudyDescription} -
- - {/* MODALITY & ACCESSION */} -
-
- {modalities || `(${t('Empty')})`} -
-
- {AccessionNumber} -
-
-
- - {/* DATE */} - {StudyDate} - - ); - - const smallRowTemplate = ( - handleClick(StudyInstanceUID)} - className={classNames({ active: isHighlighted })} - > - -
- {/* NAME AND ID */} -
-
- {PatientName || `(${t('Empty')})`} -
-
{PatientID}
-
- - {/* DESCRIPTION */} -
- {StudyDescription} -
- - {/* MODALITY & DATE */} -
-
- {modalities || `(${t('Empty')})`} -
-
{StudyDate}
-
-
- - - ); - - const rowTemplate = getContentFromUseMediaValue( - displaySize, - { - large: largeRowTemplate, - medium: mediumRowTemplate, - small: smallRowTemplate, - }, - smallRowTemplate - ); - - return rowTemplate; -} - -TableRow.propTypes = { - AccessionNumber: PropTypes.string.isRequired, - isHighlighted: PropTypes.bool, - modalities: PropTypes.string, - PatientID: PropTypes.string.isRequired, - PatientName: PropTypes.string.isRequired, - StudyDate: PropTypes.string.isRequired, - StudyDescription: PropTypes.string.isRequired, - StudyInstanceUID: PropTypes.string.isRequired, - displaySize: PropTypes.string, -}; - -TableRow.defaultProps = { - isHighlighted: false, -}; - -export { StudyList }; diff --git a/platform/ui/src/components/studyList/StudyList.styl b/platform/ui/src/components/studyList/StudyList.styl deleted file mode 100644 index 4d350f117..000000000 --- a/platform/ui/src/components/studyList/StudyList.styl +++ /dev/null @@ -1,238 +0,0 @@ -@import './../../design/styles/common/form.styl' -@import './../../design/styles/common/global.styl' - -$study-list-padding = 8%; -$study-list-toolbar-height = 75px; -$body-cell-height = 40px; -$body-cell-top-bottom-padding = 16px; - -$tablePaddingMediumScreen = 5px -$tablePaddingBigScreen = 3% -$tablePaddingLargeScreen = 5% - -// TODO: move this to a common mixin files -placeholder-color(c) - &::-webkit-input-placeholder - color: c - &:-moz-placeholder - color: c - &::-moz-placeholder - color: c - &:-ms-input-placeholder - color: c - -.study-list-header - .addNewStudy - margin: 0 10px - - label - font-weight: 400 - cursor: pointer - display: inline-block; - max-width: 100%; - margin-bottom: 5px; - - input - width: 0.1px; - height: 0.1px - opacity: 0 - overflow: hidden - position: absolute - z-index: -1 - - color: var(--text-secondary-color) - - &:hover - color: var(--hover-color) - - &:active - color: var(--active-color) - -.study-list-header - display: flex; - justify-content: space-between; - background-color: var(--ui-gray-darker) - height: $study-list-toolbar-height - margin-bottom: 2px - padding: 0 $study-list-padding - line-height: $study-list-toolbar-height - - .header - font-size: 22px - font-weight: 300 - color: var(--table-text-secondary-color) - line-height: $study-list-toolbar-height - - .actions - display: flex; - - .study-count - color: var(--large-numbers-color) - font-size: 40px - font-weight: 100 - line-height: $study-list-toolbar-height - -/* - * Dark gray background with blue border - * Spans width of page to create a distinct area for table filters - */ -.table-head-background - height: 121px - position: absolute - width: 100% - - &:before, &:after - content: '' - display: block - left: 0 - position: absolute - width: 100% - - &:before - background-color: var(--ui-gray-darker) - height: 100% - top: 0 - z-index: 1 - - &:after - background-color: var(--ui-border-color-active) - bottom: -1px - height: 1px - z-index: 2 - - -.study-list-container - width: 100% - padding: 0 $study-list-padding - position: absolute - z-index: 2 - -table.table - width: 100%; - margin-bottom: 20px; - border-spacing: 0; - border-collapse: collapse; - table-layout: fixed; - color: var(--table-text-primary-color) - font-weight: 300 - - > tbody tr - padding: 5px - background-color: black - - > tbody td - padding: $body-cell-top-bottom-padding 8px; - height: $body-cell-height - word-wrap: break-word; - - /* Striped Variant */ - &.table--striped > tbody tr:nth-child(even) - background-color: var(--ui-gray-darker) - - /* Hover Variant */ - &.table--hoverable > tbody tr - &:hover, &:active, &.active - background-color: var(--table-hover-color) - &.no-hover - &:hover, &:active, &.active - background-color: var(--ui-gray-darker) - - .empty-value - color: var(--ui-gray-light) - -.study-list-container > table.table > tr - height: 20px - -.study-list-container > table.table > thead - ::-webkit-datetime-edit-year-field:not([aria-valuenow]), - ::-webkit-datetime-edit-month-field:not([aria-valuenow]), - ::-webkit-datetime-edit-day-field:not([aria-valuenow]) - color: transparent - -.study-list-container > table.table > thead > tr > th - padding: 0; - border-bottom: 1px solid var(--ui-border-color-active); - width: 100%; - text-align: left; - border-top: 0; - -.study-list-container > table.table > thead > tr > th.StudyDate - min-width: 230px -.study-list-container > table.table .modalities - font-weight: 500; - min-height: 20px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - -.study-list-container - .filters - label - display: flex; - align-items: center; - cursor: pointer; - width: 100%; - min-width: 95px; - margin: 0 auto; - color: var(--table-text-primary-color); - font-weight: 400; - padding: 20px 8px; - user-select: none; - font-size: 15px; - - &:hover - color: var(--active-color); - - &.active, &:active - color: var(--active-color); - i - margin: 0 5px; - - input - height: 40px - margin: 0 5px 20px 5px - padding: 0 20px - cursor: pointer - border: none - background-color: var(--input-background-color) - color: var(--input-placeholder-color) - font-size: 10pt - font-weight: normal - border-radius: 4px - width: calc(100% - 10px); /* Just use padding? */ - transition(all 0.15s ease) - placeholder-color(var(--input-placeholder-color)) - - &:active, &:hover - background-color: var(--input-background-color) - - .loading-text - color: var(--table-text-secondary-color) - text-align: center; - font-size: 30px - - .notFound - color: var(--table-text-secondary-color) - font-size: 30px - font-weight: 200 - text-align: center - -@media only screen and (max-width: 768px) - .study-list-header - padding: 0 16px; - - .study-list-container - padding: 0; - - .study-list-container > table.table > thead > tr > th - padding: 0 13px; - - .study-list-container > table.table > tbody > tr > td - padding: 8px; - - .study-list-container .filters label - padding: 8px; - -@media only screen and (max-width: 500px) - .hide-xs - display: none; diff --git a/platform/ui/src/components/studyList/TablePagination.js b/platform/ui/src/components/studyList/TablePagination.js deleted file mode 100644 index ea6ed280f..000000000 --- a/platform/ui/src/components/studyList/TablePagination.js +++ /dev/null @@ -1,106 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import './PaginationArea.styl'; -import { withTranslation } from '../../contextProviders'; - -class TablePagination extends PureComponent { - static defaultProps = { - pageOptions: [5, 10, 25, 50, 100], - rowsPerPage: 25, - currentPage: 0, - }; - - static propTypes = { - /* Values to show in "Rows per page" select dropdown */ - pageOptions: PropTypes.array, - rowsPerPage: PropTypes.number.isRequired, - currentPage: PropTypes.number.isRequired, - nextPageFunc: PropTypes.func, - prevPageFunc: PropTypes.func, - onRowsPerPageChange: PropTypes.func, - recordCount: PropTypes.number.isRequired, - }; - - nextPage = () => { - this.props.nextPageFunc(this.props.currentPage); - }; - - prevPage = () => { - this.props.prevPageFunc(this.props.currentPage); - }; - - onRowsPerPageChange = event => { - this.props.onRowsPerPageChange(parseInt(event.target.value)); - }; - - renderPaginationButtons() { - return ( -
-
- -
    -
  • - -
  • -
  • - -
  • -
-
-
-
- ); - } - - renderRowsPerPageDropdown() { - return ( -
- {this.props.t('Show')} - - {this.props.t('RowsPerPage')} -
- ); - } - - render() { - return ( -
-
{this.renderRowsPerPageDropdown()}
-
-
- {this.renderPaginationButtons()} -
-
-
- ); - } -} - -const connectedComponent = withTranslation('Common')(TablePagination); -export { connectedComponent as TablePagination }; diff --git a/platform/ui/src/components/studyList/__docs__/onSearch.js b/platform/ui/src/components/studyList/__docs__/onSearch.js deleted file mode 100644 index 17c7deb91..000000000 --- a/platform/ui/src/components/studyList/__docs__/onSearch.js +++ /dev/null @@ -1,72 +0,0 @@ -import moment from 'moment'; - -export default function(searchData) { - this.setState({ searchData }); - - const filter = (key, searchData, study) => { - if (key === 'studyDateFrom' && searchData[key] && study['StudyDate']) { - const StudyDate = moment(study['StudyDate'], 'YYYYMMDD'); - return StudyDate.isBetween( - searchData['studyDateFrom'], - searchData['studyDateTo'], - 'days', - '[]' - ); - } else if (searchData[key] && !study[key].includes(searchData[key])) { - return false; - } else { - return true; - } - }; - - const { field, order } = searchData.sortData; - - // just a example of local filtering - let filteredStudies = this.defaultStudies - .filter(function(study) { - const all = [ - 'PatientName', - 'PatientID', - 'AccessionNumber', - 'modalities', - 'StudyDescription', - 'studyDateFrom', - ].every(key => { - return filter(key, searchData, study); - }); - - return all; - }) - .sort(function(a, b) { - if (order === 'desc') { - if (a[field] < b[field]) { - return -1; - } - if (a[field] > b[field]) { - return 1; - } - return 0; - } else { - if (a[field] > b[field]) { - return -1; - } - if (a[field] < b[field]) { - return 1; - } - return 0; - } - }); - - // User can notice the loading icon - return new Promise(resolve => { - setTimeout(() => { - const first = searchData.currentPage * searchData.rowsPerPage; - let last = - searchData.currentPage * searchData.rowsPerPage + - searchData.rowsPerPage; - last = last >= filteredStudies.length ? filteredStudies.length : last; - this.setState({ studies: filteredStudies.slice(first, last) }); - resolve(); - }, 500); - }); -} diff --git a/platform/ui/src/components/studyList/__docs__/studies.js b/platform/ui/src/components/studyList/__docs__/studies.js deleted file mode 100644 index 86de8c647..000000000 --- a/platform/ui/src/components/studyList/__docs__/studies.js +++ /dev/null @@ -1,87 +0,0 @@ -import moment from 'moment'; - -const studies = [ - { - StudyInstanceUID: '11111.111111.111111.11111', - PatientName: 'John Doe', - PatientID: '1', - AccessionNumber: '1234567', - StudyDate: '19930201', - modalities: 'MR', - StudyDescription: 'BRAIN', - }, - { - StudyInstanceUID: '2222.222222.22222.22222', - PatientName: 'José Silva', - PatientID: '2', - AccessionNumber: '7654321', - StudyDate: moment().format('YYYYMMDD'), - modalities: 'CT', - StudyDescription: 'PET CT STANDARD', - }, - { - StudyInstanceUID: '3333.333333.33333.33333', - PatientName: 'Antônio Jefferson', - PatientID: '3', - AccessionNumber: '732311', - StudyDate: moment() - .subtract(14, 'days') - .format('YYYYMMDD'), - modalities: 'US', - StudyDescription: '0', - }, - { - StudyInstanceUID: '444444.44444.44444.4444', - PatientName: 'Antonio da Silva', - PatientID: '4', - AccessionNumber: '732311', - StudyDate: moment() - .subtract(1, 'months') - .format('YYYYMMDD'), - modalities: 'US', - StudyDescription: '0', - }, - { - StudyInstanceUID: '55555.55555.55555.55555', - PatientName: 'Bezerra Souza', - PatientID: '5', - AccessionNumber: '5134543', - StudyDate: moment() - .subtract(6, 'days') - .format('YYYYMMDD'), - modalities: 'US', - StudyDescription: '0', - }, - { - StudyInstanceUID: '66666.66666.66666.6666', - PatientName: 'Geraldo Roger', - PatientID: '6', - AccessionNumber: '5315135', - StudyDate: moment() - .subtract(7, 'days') - .format('YYYYMMDD'), - modalities: 'US', - StudyDescription: 'US', - }, - { - StudyInstanceUID: '77777.77777.77777.77777', - PatientName: '', - PatientID: '7', - AccessionNumber: '5315136', - StudyDate: moment() - .subtract(5, 'days') - .format('YYYYMMDD'), - modalities: 'US', - StudyDescription: 'US', - }, -].sort(function(a, b) { - if (a.PatientName < b.PatientName) { - return -1; - } - if (a.PatientName > b.PatientName) { - return 1; - } - return 0; -}); - -export default studies; diff --git a/platform/ui/src/components/studyList/__docs__/studyList.mdx b/platform/ui/src/components/studyList/__docs__/studyList.mdx deleted file mode 100644 index a782aa9d1..000000000 --- a/platform/ui/src/components/studyList/__docs__/studyList.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: Study List -menu: Components -route: /components/study-list ---- - -import { Playground, Props } from 'docz' -import { State } from 'react-powerplug' -import { StudyList } from './../index.js' -// Data -import defaultStudies from './studies.js' -import onSearch from './onSearch.js' -import moment from 'moment' - -# Study List - -## Basic usage - - - { - const StudyDate = moment(study['StudyDate'], 'YYYYMMDD'); - const startDate = moment().subtract(5, 'days'); - const endDate = moment(); - - return StudyDate.isBetween(startDate, endDate, 'days', '[]'); - }).slice(0, 5) - }}> - {({ state, setState }) => ( -
-
- alert('Import study mock ' + e)} - onSelectItem={(StudyInstanceUID) => { alert(StudyInstanceUID + ' has selected! Now you can open your study.'); }} - rowsPerPage={5} - defaultSort={{ field: 'PatientName', order: 'desc', }} - studyListDateFilterNumDays={7} - onSearch={onSearch.bind({ setState, defaultStudies })} - /> -
-
- )} -
- -
- -## API - - diff --git a/platform/ui/src/components/tableList/TableList.js b/platform/ui/src/components/tableList/TableList.js deleted file mode 100644 index 86fd17620..000000000 --- a/platform/ui/src/components/tableList/TableList.js +++ /dev/null @@ -1,44 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -import './TableList.styl'; - -export class TableList extends Component { - static propTypes = { - customHeader: PropTypes.node, - defaultItems: PropTypes.object, - children: PropTypes.node.isRequired, - headerTitle: PropTypes.string, - headless: PropTypes.bool, - }; - - static defaultProps = { - headless: false, - }; - - render() { - return ( -
- {!this.props.headless && ( -
- {this.getHeader()} -
- )} -
{this.props.children}
-
- ); - } - - getHeader = () => { - if (this.props.customHeader) { - return this.props.customHeader; - } else { - return ( - -
{this.props.headerTitle}
-
{this.props.children.length}
-
- ); - } - }; -} diff --git a/platform/ui/src/components/tableList/TableListItem.js b/platform/ui/src/components/tableList/TableListItem.js deleted file mode 100644 index b3b64d6a1..000000000 --- a/platform/ui/src/components/tableList/TableListItem.js +++ /dev/null @@ -1,53 +0,0 @@ -import './TableListItem.styl'; - -import { Component } from 'react'; -import { Icon } from './../../elements/Icon'; -import PropTypes from 'prop-types'; -import React from 'react'; - -export class TableListItem extends Component { - static propTypes = { - children: PropTypes.node, - itemClass: PropTypes.string, - itemIndex: PropTypes.number, - itemMeta: PropTypes.node, - itemMetaClass: PropTypes.string, - itemKey: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), - onItemClick: PropTypes.func.isRequired, - }; - - static defaultProps = { - itemMeta: null, - itemMetaClass: '' - }; - - render() { - return ( -
-
- {this.props.itemIndex} - {this.props.itemMeta} - - - -
-
{this.props.children}
-
- ); - } - - onItemClick = event => { - if (this.props.onItemClick) { - event.preventDefault(); - event.stopPropagation(); - - this.props.onItemClick(event, this.props.itemKey); - } - }; -} diff --git a/platform/ui/src/elements/Icon/getIcon.js b/platform/ui/src/elements/Icon/getIcon.js deleted file mode 100644 index cbd6a1516..000000000 --- a/platform/ui/src/elements/Icon/getIcon.js +++ /dev/null @@ -1,194 +0,0 @@ -import React from 'react'; -import adjust from './icons/adjust.svg'; -// Icons -import angleDoubleDown from './icons/angle-double-down.svg'; -import angleDoubleUp from './icons/angle-double-up.svg'; -import angleLeft from './icons/angle-left.svg'; -import arrows from './icons/arrows.svg'; -import arrowsAltH from './icons/arrows-alt-h.svg'; -import arrowsAltV from './icons/arrows-alt-v.svg'; -import bars from './icons/bars.svg'; -import brain from './icons/brain.svg'; -import brush from './icons/brush.svg'; -import caretDown from './icons/caret-down.svg'; -import caretUp from './icons/caret-up.svg'; -import check from './icons/check.svg'; -import checkCircle from './icons/check-circle.svg'; -import checkCircleO from './icons/check-circle-o.svg'; -import chevronDown from './icons/chevron-down.svg'; -import circle from './icons/circle.svg'; -import circleNotch from './icons/circle-notch.svg'; -import circleO from './icons/circle-o.svg'; -import cog from './icons/cog.svg'; -import createComment from './icons/create-comment.svg'; -import createScreenCapture from './icons/create-screen-capture.svg'; -import crosshairs from './icons/crosshairs.svg'; -import cube from './icons/cube.svg'; -import d3Rotate from './icons/3d-rotate.svg'; -import database from './icons/database.svg'; -import dotCircle from './icons/dot-circle.svg'; -import edit from './icons/edit.svg'; -import ellipseCircle from './icons/ellipse-circle.svg'; -import ellipseH from './icons/ellipse-h.svg'; -import ellipseV from './icons/ellipse-v.svg'; -import exclamationCircle from './icons/exclamation-circle.svg'; -import exclamationTriangle from './icons/exclamation-triangle.svg'; -import fastBackward from './icons/fast-backward.svg'; -import fastForward from './icons/fast-forward.svg'; -import stop from './icons/stop.svg'; -import info from './icons/info.svg'; -import inlineEdit from './icons/inline-edit.svg'; -import level from './icons/level.svg'; -import link from './icons/link.svg'; -import linkCircles from './icons/link-circles.svg'; -import list from './icons/list.svg'; -import liver from './icons/liver.svg'; -import lock from './icons/lock.svg'; -import lockAlt from './icons/lock-alt.svg'; -import lung from './icons/lung.svg'; -import measureNonTarget from './icons/measure-non-target.svg'; -import measureTarget from './icons/measure-target.svg'; -import measureTargetCr from './icons/measure-target-cr.svg'; -import measureTargetNe from './icons/measure-target-ne.svg'; -import measureTargetUn from './icons/measure-target-un.svg'; -import measureTemp from './icons/measure-temp.svg'; -import objectGroup from './icons/object-group.svg'; -import ohifLogo from './icons/ohif-logo.svg'; -import ohifTextLogo from './icons/ohif-text-logo.svg'; -import oval from './icons/oval.svg'; -import palette from './icons/palette.svg'; -import play from './icons/play.svg'; -import plus from './icons/plus.svg'; -import powerOff from './icons/power-off.svg'; -import reset from './icons/reset.svg'; -import rotate from './icons/rotate.svg'; -import rotateRight from './icons/rotate-right.svg'; -import saveRegular from './icons/save-regular.svg'; -import scissors from './icons/scissors.svg'; -import search from './icons/search.svg'; -import searchPlus from './icons/search-plus.svg'; -import softTissue from './icons/soft-tissue.svg'; -import sort from './icons/sort.svg'; -import sortDown from './icons/sort-down.svg'; -import sortUp from './icons/sort-up.svg'; -import sphere from './icons/sphere.svg'; -import squareO from './icons/square-o.svg'; -import star from './icons/star.svg'; -import stepBackward from './icons/step-backward.svg'; -import stepForward from './icons/step-forward.svg'; -import sun from './icons/sun.svg'; -import th from './icons/th.svg'; -import thLarge from './icons/th-large.svg'; -import thList from './icons/th-list.svg'; -import times from './icons/times.svg'; -import trash from './icons/trash.svg'; -import unlink from './icons/unlink.svg'; -import user from './icons/user.svg'; -import youtube from './icons/youtube.svg'; -import eye from './icons/eye.svg'; -import eyeClosed from './icons/eye-closed.svg'; - -const ICONS = { - eye, - 'eye-closed': eyeClosed, - brush, - scissors, - user, - sort, - th, - star, - 'sort-up': sortUp, - sphere, - 'sort-down': sortDown, - info, - cube, - crosshairs, - 'dot-circle': dotCircle, - 'angle-left': angleLeft, - '3d-rotate': d3Rotate, - plus, - 'chevron-down': chevronDown, - 'angle-double-down': angleDoubleDown, - 'angle-double-up': angleDoubleUp, - 'arrows-alt-h': arrowsAltH, - 'arrows-alt-v': arrowsAltV, - bars, - 'caret-down': caretDown, - 'caret-up': caretUp, - 'check-circle-o': checkCircleO, - check, - circle, - 'circle-o': circleO, - times, - 'create-comment': createComment, - 'create-screen-capture': createScreenCapture, - edit, - 'fast-backward': fastBackward, - 'fast-forward': fastForward, - 'object-group': objectGroup, - search, - 'power-off': powerOff, - 'inline-edit': inlineEdit, - list, - 'ohif-logo': ohifLogo, - 'ohif-text-logo': ohifTextLogo, - lock, - play, - database, - cog, - 'circle-notch': circleNotch, - 'square-o': squareO, - 'check-circle': checkCircle, - 'lock-alt': lockAlt, - 'step-backward': stepBackward, - 'step-forward': stepForward, - stop, - 'th-large': thLarge, - 'th-list': thList, - sun, - palette, - youtube, - oval, - 'ellipse-h': ellipseH, - 'ellipse-v': ellipseV, - adjust, - level, - 'link-circles': linkCircles, - 'search-plus': searchPlus, - 'measure-non-target': measureNonTarget, - 'measure-target': measureTarget, - 'measure-target-cr': measureTargetCr, - 'measure-target-un': measureTargetUn, - 'measure-target-ne': measureTargetNe, - 'measure-temp': measureTemp, - 'ellipse-circle': ellipseCircle, - arrows, - reset, - rotate, - 'rotate-right': rotateRight, - trash, - unlink, - 'exclamation-circle': exclamationCircle, - link, - 'exclamation-triangle': exclamationTriangle, - brain, - 'soft-tissue': softTissue, - lung, - liver, - save: saveRegular, -}; - -/** - * Return the matching SVG Icon as a React Component. - * Results in an inlined SVG Element. If there's no match, - * return `null` - */ -export default function getIcon(key, props) { - if (!key || !ICONS[key]) { - return React.createElement('div', null, 'Missing Icon'); - } - - return React.createElement(ICONS[key], props); -} - -export { ICONS }; diff --git a/platform/ui/src/elements/Icon/icons/brush.svg b/platform/ui/src/elements/Icon/icons/brush.svg deleted file mode 100644 index 7786f4259..000000000 --- a/platform/ui/src/elements/Icon/icons/brush.svg +++ /dev/null @@ -1,11 +0,0 @@ - - Brush - - diff --git a/platform/ui/src/elements/Icon/icons/eye-closed.svg b/platform/ui/src/elements/Icon/icons/eye-closed.svg deleted file mode 100644 index 5d4907dc0..000000000 --- a/platform/ui/src/elements/Icon/icons/eye-closed.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/platform/ui/src/elements/Icon/icons/eye.svg b/platform/ui/src/elements/Icon/icons/eye.svg deleted file mode 100644 index 5686375b8..000000000 --- a/platform/ui/src/elements/Icon/icons/eye.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/platform/ui/src/elements/Icon/icons/scissors.svg b/platform/ui/src/elements/Icon/icons/scissors.svg deleted file mode 100644 index b3b852376..000000000 --- a/platform/ui/src/elements/Icon/icons/scissors.svg +++ /dev/null @@ -1,11 +0,0 @@ - - Scissors - - diff --git a/platform/ui/src/elements/Icon/icons/sphere.svg b/platform/ui/src/elements/Icon/icons/sphere.svg deleted file mode 100644 index e4620d98d..000000000 --- a/platform/ui/src/elements/Icon/icons/sphere.svg +++ /dev/null @@ -1,21 +0,0 @@ - - Sphere - - - diff --git a/platform/ui/src/elements/form/Range.js b/platform/ui/src/elements/form/Range.js deleted file mode 100644 index a3454f213..000000000 --- a/platform/ui/src/elements/form/Range.js +++ /dev/null @@ -1,53 +0,0 @@ -import './Range.css'; - -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -class Range extends Component { - constructor(props) { - super(props); - this.state = { value: props.value || 0 }; - } - - handleChange = event => { - this.setState({ value: event.target.value }); - if (this.props.onChange) this.props.onChange(event); - }; - - render() { - return ( - <> - - {this.props.showPercentage && {`${this.state.value}%`}} - {this.props.showValue && {this.state.value}} - - ); - } -} - -Range.propTypes = { - value: PropTypes.number, - min: PropTypes.number.isRequired, - max: PropTypes.number.isRequired, - step: PropTypes.number, - id: PropTypes.string, - onChange: PropTypes.func, - showPercentage: PropTypes.bool, - showValue: PropTypes.bool, -}; - -Range.defaultProps = { - showPercentage: false, - showValue: false, -}; - -export { Range }; diff --git a/platform/ui/src/elements/form/TextArea.js b/platform/ui/src/elements/form/TextArea.js deleted file mode 100644 index 6c53e3daf..000000000 --- a/platform/ui/src/elements/form/TextArea.js +++ /dev/null @@ -1,39 +0,0 @@ -import './TextArea.css'; - -import React from 'react'; -import PropTypes from 'prop-types'; - -class TextArea extends React.Component { - constructor(props) { - super(props); - this.state = { value: this.props.value }; - } - - handleChange = event => { - this.setState({ value: event.target.value }); - if (this.props.onChange) this.props.onChange(); - }; - - render() { - return ( -