diff --git a/extensions/default/src/Panels/PanelStudyBrowser.tsx b/extensions/default/src/Panels/PanelStudyBrowser.tsx index af2d232fb..650fd6c90 100644 --- a/extensions/default/src/Panels/PanelStudyBrowser.tsx +++ b/extensions/default/src/Panels/PanelStudyBrowser.tsx @@ -4,7 +4,7 @@ import { StudyBrowser, useImageViewer, useViewportGrid } from '@ohif/ui'; import { utils } from '@ohif/core'; import { useNavigate } from 'react-router-dom'; -const { sortStudyInstances, formatDate } = utils; +const { sortStudyInstances, formatDate, createStudyBrowserTabs } = utils; /** * @@ -206,7 +206,7 @@ function PanelStudyBrowser({ }; }, [StudyInstanceUIDs, thumbnailImageSrcMap, displaySetService]); - const tabs = _createStudyBrowserTabs(StudyInstanceUIDs, studyDisplayList, displaySets); + const tabs = createStudyBrowserTabs(StudyInstanceUIDs, studyDisplayList, displaySets); // TODO: Should not fire this on "close" function _handleStudyClick(StudyInstanceUID) { @@ -324,58 +324,3 @@ function _getComponentType(ds) { return 'thumbnail'; } - -/** - * - * @param {string[]} primaryStudyInstanceUIDs - * @param {object[]} studyDisplayList - * @param {string} studyDisplayList.studyInstanceUid - * @param {string} studyDisplayList.date - * @param {string} studyDisplayList.description - * @param {string} studyDisplayList.modalities - * @param {number} studyDisplayList.numInstances - * @param {object[]} displaySets - * @returns tabs - The prop object expected by the StudyBrowser component - */ -function _createStudyBrowserTabs(primaryStudyInstanceUIDs, studyDisplayList, displaySets) { - const primaryStudies = []; - const recentStudies = []; - const allStudies = []; - - studyDisplayList.forEach(study => { - const displaySetsForStudy = displaySets.filter( - ds => ds.StudyInstanceUID === study.studyInstanceUid - ); - const tabStudy = Object.assign({}, study, { - displaySets: displaySetsForStudy, - }); - - if (primaryStudyInstanceUIDs.includes(study.studyInstanceUid)) { - primaryStudies.push(tabStudy); - } else { - // TODO: Filter allStudies to dates within one year of current date - recentStudies.push(tabStudy); - allStudies.push(tabStudy); - } - }); - - const tabs = [ - { - name: 'primary', - label: 'Primary', - studies: primaryStudies, - }, - { - name: 'recent', - label: 'Recent', - studies: recentStudies, - }, - { - name: 'all', - label: 'All', - studies: allStudies, - }, - ]; - - return tabs; -} diff --git a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx index d6f6e0844..a59a40f4c 100644 --- a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx +++ b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx @@ -6,7 +6,7 @@ import { utils } from '@ohif/core'; import { StudyBrowser, useImageViewer, useViewportGrid, Dialog, ButtonEnums } from '@ohif/ui'; import { useTrackedMeasurements } from '../../getContextModule'; -const { formatDate } = utils; +const { formatDate, createStudyBrowserTabs } = utils; /** * @@ -272,11 +272,10 @@ function PanelStudyBrowserTracking({ }; }, [thumbnailImageSrcMap, trackedSeries, viewports, dataSource, displaySetService]); - const tabs = _createStudyBrowserTabs( + const tabs = createStudyBrowserTabs( StudyInstanceUIDs, studyDisplayList, displaySets, - hangingProtocolService ); // TODO: Should not fire this on "close" @@ -590,97 +589,6 @@ function _getComponentType(ds) { return 'thumbnailTracked'; } -/** - * - * @param {string[]} primaryStudyInstanceUIDs - * @param {object[]} studyDisplayList - * @param {string} studyDisplayList.studyInstanceUid - * @param {string} studyDisplayList.date - * @param {string} studyDisplayList.description - * @param {string} studyDisplayList.modalities - * @param {number} studyDisplayList.numInstances - * @param {object[]} displaySets - * @returns tabs - The prop object expected by the StudyBrowser component - */ -function _createStudyBrowserTabs( - primaryStudyInstanceUIDs, - studyDisplayList, - displaySets, - hangingProtocolService -) { - const primaryStudies = []; - const recentStudies = []; - const allStudies = []; - - // Iterate over each study... - studyDisplayList.forEach(study => { - // Find it's display sets - const displaySetsForStudy = displaySets.filter( - ds => ds.StudyInstanceUID === study.studyInstanceUid - ); - - // Sort them - const dsSortFn = hangingProtocolService.getDisplaySetSortFunction(); - displaySetsForStudy.sort(dsSortFn); - - /* Sort by series number, then by series date - displaySetsForStudy.sort((a, b) => { - if (a.seriesNumber !== b.seriesNumber) { - return a.seriesNumber - b.seriesNumber; - } - - const seriesDateA = Date.parse(a.seriesDate); - const seriesDateB = Date.parse(b.seriesDate); - - return seriesDateA - seriesDateB; - }); - */ - - // Map the study to it's tab/view representation - const tabStudy = Object.assign({}, study, { - displaySets: displaySetsForStudy, - }); - - // Add the "tab study" to the 'primary', 'recent', and/or 'all' tab group(s) - if (primaryStudyInstanceUIDs.includes(study.studyInstanceUid)) { - primaryStudies.push(tabStudy); - allStudies.push(tabStudy); - } else { - // TODO: Filter allStudies to dates within one year of current date - recentStudies.push(tabStudy); - allStudies.push(tabStudy); - } - }); - - // Newest first - const _byDate = (a, b) => { - const dateA = Date.parse(a); - const dateB = Date.parse(b); - - return dateB - dateA; - }; - - const tabs = [ - { - name: 'primary', - label: 'Primary', - studies: primaryStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date)), - }, - { - name: 'recent', - label: 'Recent', - studies: recentStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date)), - }, - { - name: 'all', - label: 'All', - studies: allStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date)), - }, - ]; - - return tabs; -} - function _findTabAndStudyOfDisplaySet(displaySetInstanceUID, tabs) { for (let t = 0; t < tabs.length; t++) { const { studies } = tabs[t]; diff --git a/platform/core/src/utils/createStudyBrowserTabs.ts b/platform/core/src/utils/createStudyBrowserTabs.ts new file mode 100644 index 000000000..06ef4a40a --- /dev/null +++ b/platform/core/src/utils/createStudyBrowserTabs.ts @@ -0,0 +1,77 @@ +/** + * + * @param {string[]} primaryStudyInstanceUIDs + * @param {object[]} studyDisplayList + * @param {string} studyDisplayList.studyInstanceUid + * @param {string} studyDisplayList.date + * @param {string} studyDisplayList.description + * @param {string} studyDisplayList.modalities + * @param {number} studyDisplayList.numInstances + * @param {object[]} displaySets + * @param {number} recentTimeframe - The number of milliseconds to consider a study recent + * @returns tabs - The prop object expected by the StudyBrowser component + */ + +export function createStudyBrowserTabs(primaryStudyInstanceUIDs, studyDisplayList, displaySets, recentTimeframeMS = 31536000000) { + const primaryStudies = []; + const allStudies = []; + + studyDisplayList.forEach(study => { + const displaySetsForStudy = displaySets.filter( + ds => ds.StudyInstanceUID === study.studyInstanceUid + ); + const tabStudy = Object.assign({}, study, { + displaySets: displaySetsForStudy, + }); + + if (primaryStudyInstanceUIDs.includes(study.studyInstanceUid)) { + primaryStudies.push(tabStudy); + } + allStudies.push(tabStudy); + }); + + const primaryStudiesTimestamps = primaryStudies + .filter(study => study.date) + .map(study => new Date(study.date).getTime()); + + const recentStudies = + primaryStudiesTimestamps.length > 0 + ? allStudies.filter(study => { + const oldestPrimaryTimeStamp = Math.min(...primaryStudiesTimestamps); + + if (!study.date) { + return false; + } + const studyTimeStamp = new Date(study.date).getTime(); + console.log(oldestPrimaryTimeStamp, studyTimeStamp, recentTimeframeMS) + return oldestPrimaryTimeStamp - studyTimeStamp < recentTimeframeMS; + }) + : []; + + // Newest first + const _byDate = (a, b) => { + const dateA = Date.parse(a); + const dateB = Date.parse(b); + + return dateB - dateA; + }; + const tabs = [ + { + name: 'primary', + label: 'Primary', + studies: primaryStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date)), + }, + { + name: 'recent', + label: 'Recent', + studies: recentStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date)), + }, + { + name: 'all', + label: 'All', + studies: allStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date)), + }, + ]; + + return tabs; +} diff --git a/platform/core/src/utils/index.ts b/platform/core/src/utils/index.ts index d7862618e..a22f8a7ef 100644 --- a/platform/core/src/utils/index.ts +++ b/platform/core/src/utils/index.ts @@ -37,6 +37,7 @@ import { } from './sortStudy'; import { subscribeToNextViewportGridChange } from './subscribeToNextViewportGridChange'; import { splitComma, getSplitParam } from './splitComma'; +import { createStudyBrowserTabs } from './createStudyBrowserTabs'; // Commented out unused functionality. // Need to implement new mechanism for derived displaySets using the displaySetManager. @@ -80,6 +81,7 @@ const utils = { splitComma, getSplitParam, generateAcceptHeader, + createStudyBrowserTabs, }; export { @@ -112,6 +114,7 @@ export { splitComma, getSplitParam, generateAcceptHeader, + createStudyBrowserTabs, }; export default utils; diff --git a/yarn.lock b/yarn.lock index 6f1a6ad55..a83639a7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7732,7 +7732,7 @@ class-variance-authority@^0.7.0: dependencies: clsx "2.0.0" -classnames@^2.2.5, classnames@^2.3.2: +classnames@^2.3.2: version "2.5.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== @@ -17893,13 +17893,13 @@ react-dom@^18.3.1: loose-envify "^1.1.0" scheduler "^0.23.2" -react-draggable@4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.3.tgz#0727f2cae5813e36b0e4962bf11b2f9ef2b406f3" - integrity sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w== +react-draggable@^4.4.6: + version "4.4.6" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.6.tgz#63343ee945770881ca1256a5b6fa5c9f5983fe1e" + integrity sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw== dependencies: - classnames "^2.2.5" - prop-types "^15.6.0" + clsx "^1.1.1" + prop-types "^15.8.1" react-dropzone@^10.1.7: version "10.2.2"