Merge branch 'feat/v2-main' of github.com:OHIF/Viewers into feat/v2-main
This commit is contained in:
commit
ec9b2e1dd0
@ -66,7 +66,7 @@ function createDicomWebApi(dicomWebConfig) {
|
|||||||
query: {
|
query: {
|
||||||
studies: {
|
studies: {
|
||||||
mapParams: mapParams.bind(),
|
mapParams: mapParams.bind(),
|
||||||
search: async function(origParams) {
|
search: async function (origParams) {
|
||||||
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
|
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
|
||||||
mapParams(origParams, {
|
mapParams(origParams, {
|
||||||
supportsFuzzyMatching,
|
supportsFuzzyMatching,
|
||||||
@ -86,7 +86,7 @@ function createDicomWebApi(dicomWebConfig) {
|
|||||||
},
|
},
|
||||||
series: {
|
series: {
|
||||||
// mapParams: mapParams.bind(),
|
// mapParams: mapParams.bind(),
|
||||||
search: async function(studyInstanceUid) {
|
search: async function (studyInstanceUid) {
|
||||||
const results = await seriesInStudy(
|
const results = await seriesInStudy(
|
||||||
qidoDicomWebClient,
|
qidoDicomWebClient,
|
||||||
studyInstanceUid
|
studyInstanceUid
|
||||||
|
|||||||
@ -2,14 +2,16 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
const stickyClasses = 'sticky top-0 z-10';
|
const stickyClasses = 'sticky top-0';
|
||||||
|
const notStickyClasses = 'relative';
|
||||||
|
|
||||||
const NavBar = ({ className, children, isSticky }) => {
|
const NavBar = ({ className, children, isSticky }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames(
|
className={classnames(
|
||||||
'flex flex-row items-center bg-secondary-dark px-3 py-1 min-h-16 border-b-4 border-black',
|
'flex flex-row items-center bg-secondary-dark px-3 py-1 min-h-16 border-b-4 border-black z-20',
|
||||||
isSticky && stickyClasses,
|
isSticky && stickyClasses,
|
||||||
|
!isSticky && notStickyClasses,
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -6,6 +6,9 @@ import { MODULE_TYPES } from '@ohif/core';
|
|||||||
import { useAppConfig } from '@state';
|
import { useAppConfig } from '@state';
|
||||||
import { extensionManager } from '../App.jsx';
|
import { extensionManager } from '../App.jsx';
|
||||||
|
|
||||||
|
let cacheMap = {};
|
||||||
|
let total = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses route properties to determine the data source that should be passed
|
* Uses route properties to determine the data source that should be passed
|
||||||
* to the child layout template. In some instances, initiates requests and
|
* to the child layout template. In some instances, initiates requests and
|
||||||
@ -17,8 +20,6 @@ import { extensionManager } from '../App.jsx';
|
|||||||
function DataSourceWrapper(props) {
|
function DataSourceWrapper(props) {
|
||||||
const [appConfig] = useAppConfig();
|
const [appConfig] = useAppConfig();
|
||||||
const { children: LayoutTemplate, history, ...rest } = props;
|
const { children: LayoutTemplate, history, ...rest } = props;
|
||||||
const queryFilterValues = _getQueryFilterValues(history.location.search);
|
|
||||||
|
|
||||||
// TODO: Fetch by type, name, etc?
|
// TODO: Fetch by type, name, etc?
|
||||||
const dataSourceModules = extensionManager.modules[MODULE_TYPES.DATA_SOURCE];
|
const dataSourceModules = extensionManager.modules[MODULE_TYPES.DATA_SOURCE];
|
||||||
// TODO: Good usecase for flatmap?
|
// TODO: Good usecase for flatmap?
|
||||||
@ -46,17 +47,61 @@ function DataSourceWrapper(props) {
|
|||||||
// studies.processResults --> <LayoutTemplate studies={} />
|
// studies.processResults --> <LayoutTemplate studies={} />
|
||||||
// But only for LayoutTemplate type of 'list'?
|
// But only for LayoutTemplate type of 'list'?
|
||||||
// Or no data fetching here, and just hand down my source
|
// Or no data fetching here, and just hand down my source
|
||||||
const [data, setData] = useState([]);
|
const STUDIES_LIMIT = 101;
|
||||||
|
const [data, setData] = useState({ studies: [], total: 0 });
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 204: no content
|
// 204: no content
|
||||||
async function getData() {
|
async function getData() {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const searchResults = await dataSource.query.studies.search(
|
|
||||||
queryFilterValues
|
const limit = STUDIES_LIMIT - 1;
|
||||||
);
|
const queryFilterValues = _getQueryFilterValues(history.location.search);
|
||||||
setData(searchResults);
|
const { resultsPerPage = 25, pageNumber = 1 } = queryFilterValues;
|
||||||
|
const reachedLimits = parseInt((resultsPerPage * pageNumber) / STUDIES_LIMIT);
|
||||||
|
const cacheKey = `${pageNumber}-${resultsPerPage}`;
|
||||||
|
|
||||||
|
const getFromCache = async ({ cacheKey, pageNumber, resultsPerPage, limit, options }) => {
|
||||||
|
const pagesAmount = limit / resultsPerPage;
|
||||||
|
const pageToRequest = parseInt((resultsPerPage * pageNumber) / STUDIES_LIMIT);
|
||||||
|
|
||||||
|
let length = 0;
|
||||||
|
if (!cacheMap[cacheKey]) {
|
||||||
|
length = pageToRequest > 0 ? (pageToRequest * STUDIES_LIMIT) : 1;
|
||||||
|
const studiesPromise = dataSource.query.studies.search(options);
|
||||||
|
|
||||||
|
for (let pageNum = 0; pageNum < pagesAmount; pageNum++) {
|
||||||
|
const currentPageNumber = (pageNum + 1) + (pageToRequest * pagesAmount);
|
||||||
|
cacheMap[`${currentPageNumber}-${resultsPerPage}`] = studiesPromise.then(function (results) {
|
||||||
|
const slicedResult = results.slice((pageNum * resultsPerPage), ((pageNum + 1) * resultsPerPage));
|
||||||
|
length += slicedResult.length;
|
||||||
|
return slicedResult;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cache = await cacheMap[cacheKey];
|
||||||
|
return { cache, length, index: pageToRequest };
|
||||||
|
};
|
||||||
|
|
||||||
|
const { cache: studies, index, length } = await getFromCache({
|
||||||
|
cacheKey,
|
||||||
|
pageNumber,
|
||||||
|
resultsPerPage,
|
||||||
|
limit,
|
||||||
|
options: { ...queryFilterValues, ...{ offset: reachedLimits * limit } }
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalKey = `${resultsPerPage}-${index}`;
|
||||||
|
total[totalKey] = total[totalKey] ? total[totalKey] + length : length;
|
||||||
|
const totals = Object.keys(total).map(key => total[key]);
|
||||||
|
const biggestIndex = totals.indexOf(Math.max(...totals));
|
||||||
|
const biggestKey = Object.keys(total)[biggestIndex];
|
||||||
|
const biggestTotal = total[biggestKey];
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
setData({ studies, total: biggestTotal });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -73,7 +118,8 @@ function DataSourceWrapper(props) {
|
|||||||
<LayoutTemplate
|
<LayoutTemplate
|
||||||
{...rest}
|
{...rest}
|
||||||
history={history}
|
history={history}
|
||||||
data={data}
|
data={data.studies}
|
||||||
|
dataTotal={data.total}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
isLoadingData={isLoading}
|
isLoadingData={isLoading}
|
||||||
/>
|
/>
|
||||||
@ -106,6 +152,7 @@ function _getQueryFilterValues(query) {
|
|||||||
startDate: query.get('startDate'),
|
startDate: query.get('startDate'),
|
||||||
endDate: query.get('endDate'),
|
endDate: query.get('endDate'),
|
||||||
page: _tryParseInt(query.get('page'), undefined),
|
page: _tryParseInt(query.get('page'), undefined),
|
||||||
|
pageNumber: _tryParseInt(query.get('pageNumber'), undefined),
|
||||||
resultsPerPage: _tryParseInt(query.get('resultsPerPage'), undefined),
|
resultsPerPage: _tryParseInt(query.get('resultsPerPage'), undefined),
|
||||||
// Rarely supported server-side
|
// Rarely supported server-side
|
||||||
sortBy: query.get('sortBy'),
|
sortBy: query.get('sortBy'),
|
||||||
|
|||||||
@ -33,15 +33,15 @@ const seriesInStudiesMap = new Map();
|
|||||||
* TODO:
|
* TODO:
|
||||||
* - debounce `setFilterValues` (150ms?)
|
* - debounce `setFilterValues` (150ms?)
|
||||||
*/
|
*/
|
||||||
function WorkList({ history, data: studies, isLoadingData, dataSource, hotkeysManager }) {
|
function WorkList({ history, data: studies, dataTotal: studiesTotal, isLoadingData, dataSource, hotkeysManager }) {
|
||||||
const { hotkeyDefinitions, hotkeyDefaults } = hotkeysManager;
|
const { hotkeyDefinitions, hotkeyDefaults } = hotkeysManager;
|
||||||
const { show, hide } = useModal();
|
const { show, hide } = useModal();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
// ~ Modes
|
// ~ Modes
|
||||||
const [appConfig] = useAppConfig();
|
const [appConfig] = useAppConfig();
|
||||||
// ~ Filters
|
// ~ Filters
|
||||||
const query = useQuery();
|
const query = useQuery();
|
||||||
|
const STUDIES_LIMIT = 101;
|
||||||
const queryFilterValues = _getQueryFilterValues(query);
|
const queryFilterValues = _getQueryFilterValues(query);
|
||||||
const [filterValues, _setFilterValues] = useState({
|
const [filterValues, _setFilterValues] = useState({
|
||||||
...defaultFilterValues,
|
...defaultFilterValues,
|
||||||
@ -64,12 +64,9 @@ function WorkList({ history, data: studies, isLoadingData, dataSource, hotkeysMa
|
|||||||
const noSortApplied = sortBy === '' || !sortBy;
|
const noSortApplied = sortBy === '' || !sortBy;
|
||||||
const sortModifier = sortDirection === 'descending' ? 1 : -1;
|
const sortModifier = sortDirection === 'descending' ? 1 : -1;
|
||||||
|
|
||||||
if (noSortApplied && studies.length < 101) {
|
if (noSortApplied && studiesTotal < STUDIES_LIMIT) {
|
||||||
const ascendingSortModifier = -1;
|
const ascendingSortModifier = -1;
|
||||||
defaultSortValues = {
|
defaultSortValues = { sortBy: 'studyDate', sortDirection: 'ascending' };
|
||||||
sortBy: 'studyDate',
|
|
||||||
sortDirection: 'ascending',
|
|
||||||
};
|
|
||||||
return _sortStringDates(s1, s2, ascendingSortModifier);
|
return _sortStringDates(s1, s2, ascendingSortModifier);
|
||||||
} else if (noSortApplied) {
|
} else if (noSortApplied) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -96,7 +93,7 @@ function WorkList({ history, data: studies, isLoadingData, dataSource, hotkeysMa
|
|||||||
// ~ Rows & Studies
|
// ~ Rows & Studies
|
||||||
const [expandedRows, setExpandedRows] = useState([]);
|
const [expandedRows, setExpandedRows] = useState([]);
|
||||||
const [studiesWithSeriesData, setStudiesWithSeriesData] = useState([]);
|
const [studiesWithSeriesData, setStudiesWithSeriesData] = useState([]);
|
||||||
const numOfStudies = studies.length;
|
const numOfStudies = studiesTotal;
|
||||||
const totalPages = Math.floor(numOfStudies / resultsPerPage) + 1;
|
const totalPages = Math.floor(numOfStudies / resultsPerPage) + 1;
|
||||||
|
|
||||||
const setFilterValues = val => {
|
const setFilterValues = val => {
|
||||||
@ -111,6 +108,7 @@ function WorkList({ history, data: studies, isLoadingData, dataSource, hotkeysMa
|
|||||||
if (newPageNumber > totalPages) {
|
if (newPageNumber > totalPages) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilterValues({ ...filterValues, pageNumber: newPageNumber });
|
setFilterValues({ ...filterValues, pageNumber: newPageNumber });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,6 +133,7 @@ function WorkList({ history, data: studies, isLoadingData, dataSource, hotkeysMa
|
|||||||
if (!debouncedFilterValues) {
|
if (!debouncedFilterValues) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryString = {};
|
const queryString = {};
|
||||||
Object.keys(defaultFilterValues).forEach(key => {
|
Object.keys(defaultFilterValues).forEach(key => {
|
||||||
const defaultValue = defaultFilterValues[key];
|
const defaultValue = defaultFilterValues[key];
|
||||||
@ -389,10 +388,7 @@ function WorkList({ history, data: studies, isLoadingData, dataSource, hotkeysMa
|
|||||||
{hasStudies ? (
|
{hasStudies ? (
|
||||||
<>
|
<>
|
||||||
<StudyListTable
|
<StudyListTable
|
||||||
tableDataSource={tableDataSource.slice(
|
tableDataSource={tableDataSource}
|
||||||
(pageNumber - 1) * resultsPerPage,
|
|
||||||
(pageNumber - 1) * resultsPerPage + resultsPerPage
|
|
||||||
)}
|
|
||||||
numOfStudies={numOfStudies}
|
numOfStudies={numOfStudies}
|
||||||
filtersMeta={filtersMeta}
|
filtersMeta={filtersMeta}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user