diff --git a/platform/ui/src/components/studyList/StudyList.js b/platform/ui/src/components/studyList/StudyList.js
index d3a8d4751..a09623f85 100644
--- a/platform/ui/src/components/studyList/StudyList.js
+++ b/platform/ui/src/components/studyList/StudyList.js
@@ -11,11 +11,79 @@ import { StudylistToolbar } from './StudyListToolbar.js';
import { isInclusivelyBeforeDay } from 'react-dates';
import moment from 'moment';
import debounce from 'lodash.debounce';
+import isEqual from 'lodash.isequal';
import { withTranslation } from '../../utils/LanguageProvider';
const today = moment();
const lastWeek = moment().subtract(7, 'day');
const lastMonth = moment().subtract(1, 'month');
+function getPaginationFragment(
+ props,
+ searchData,
+ nextPageCb,
+ prevPageCb,
+ changeRowsPerPageCb
+) {
+ return (
+
+ );
+}
+
+function getTableMeta(translate) {
+ return {
+ patientName: {
+ displayText: translate('PatientName'),
+ sort: 0,
+ },
+ patientId: {
+ displayText: translate('MRN'),
+ sort: 0,
+ },
+ accessionNumber: {
+ displayText: translate('AccessionNumber'),
+ sort: 0,
+ },
+ studyDate: {
+ displayText: translate('StudyDate'),
+ inputType: 'date-range',
+ sort: 0,
+ },
+ modalities: {
+ displayText: translate('Modality'),
+ sort: 0,
+ },
+ studyDescription: {
+ displayText: translate('StudyDescription'),
+ sort: 0,
+ },
+ };
+}
+
+function getNoListFragment(translate, studies, error, loading) {
+ if (loading) {
+ return (
+
{this.props.t('StudyList')}
-
- {this.props.studies.length}
-
+
{studiesNum}
{this.props.studyListFunctionsEnabled ? (
@@ -367,22 +437,16 @@ class StudyList extends Component {
(this.state.focusedInput === 'endDate' ||
preset)
) {
- this.setSearchDataBatch(
- {
- studyDateFrom: startDate.toDate(),
- studyDateTo: endDate.toDate(),
- },
- this.search
- );
+ this.setSearchDataBatch({
+ studyDateFrom: startDate.toDate(),
+ studyDateTo: endDate.toDate(),
+ });
this.setState({ focusedInput: false });
} else if (!startDate && !endDate) {
- this.setSearchDataBatch(
- {
- studyDateFrom: null,
- studyDateTo: null,
- },
- this.search
- );
+ this.setSearchDataBatch({
+ studyDateFrom: null,
+ studyDateTo: null,
+ });
}
}}
focusedInput={this.state.focusedInput}
@@ -398,26 +462,18 @@ class StudyList extends Component {
})}
-
- {this.props.studies.map(study => {
- return this.renderTableRow(study);
- })}
-
+
{tableBody}
- {this.renderIsLoading()}
- {this.renderHasError()}
- {this.renderNoMachingResults()}
-
-
+ {noListFragment
+ ? noListFragment
+ : getPaginationFragment(
+ this.props,
+ this.state.searchData,
+ this.nextPage,
+ this.prevPage,
+ this.onRowsPerPageChange
+ )}
);
diff --git a/platform/ui/src/components/studyList/StudyList.styl b/platform/ui/src/components/studyList/StudyList.styl
index 9cefa7a5d..c4cf6a767 100644
--- a/platform/ui/src/components/studyList/StudyList.styl
+++ b/platform/ui/src/components/studyList/StudyList.styl
@@ -82,9 +82,14 @@ placeholder-color(c)
position: absolute
z-index: 2
- .loading-text
- color: var(--table-text-secondary-color)
- font-size: 30px
+ .loading
+ display: flex;
+ justify-content: center;
+
+ .loading-text
+ color: var(--table-text-secondary-color)
+ font-size: 30px
+ width: fit-content;
.notFound
color: var(--table-text-secondary-color)
diff --git a/platform/ui/src/components/studyList/StudyListLoadingText.js b/platform/ui/src/components/studyList/StudyListLoadingText.js
index deab2e331..22c0dad74 100644
--- a/platform/ui/src/components/studyList/StudyListLoadingText.js
+++ b/platform/ui/src/components/studyList/StudyListLoadingText.js
@@ -1,12 +1,17 @@
import { Icon } from './../../elements/Icon';
import React from 'react';
+import { withTranslation } from '../../utils/LanguageProvider';
-function StudyListLoadingText() {
+function StudyListLoadingText({ t: translate }) {
return (
- Loading...
+ {translate('Loading')}...
);
}
-export { StudyListLoadingText };
+const connectedComponent = withTranslation('StudyListLoadingText')(
+ StudyListLoadingText
+);
+
+export { connectedComponent as StudyListLoadingText };
diff --git a/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js b/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js
index b79a4598c..5d5f7671f 100644
--- a/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js
+++ b/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js
@@ -1,6 +1,6 @@
describe('OHIFStandaloneViewer', () => {
beforeEach(() => {
- cy.visit('/');
+ cy.openStudyList();
});
it('loads route with at least 2 rows', () => {
diff --git a/platform/viewer/cypress/support/aliases.js b/platform/viewer/cypress/support/aliases.js
index c32aa728d..ec9a246eb 100644
--- a/platform/viewer/cypress/support/aliases.js
+++ b/platform/viewer/cypress/support/aliases.js
@@ -35,8 +35,8 @@ export function initCommonElementsAliases() {
//Creating aliases for Routes
export function initRouteAliases() {
cy.server();
- cy.route('GET', '/**/series/**').as('getStudySeries');
- cy.route('GET', '/**/studies/**').as('getStudies');
+ cy.route('GET', '**/series**').as('getStudySeries');
+ cy.route('GET', '**/studies**').as('getStudies');
}
//Creating aliases for VTK tools buttons
diff --git a/platform/viewer/cypress/support/commands.js b/platform/viewer/cypress/support/commands.js
index 5981b9cf4..05edbabfd 100644
--- a/platform/viewer/cypress/support/commands.js
+++ b/platform/viewer/cypress/support/commands.js
@@ -39,20 +39,12 @@ import {
* @param {string} PatientName - Patient name that we would like to search for
*/
Cypress.Commands.add('openStudy', patientName => {
- cy.initRouteAliases();
- cy.visit('/');
- cy.wrap(null).then(() => {
- return new Cypress.Promise((resolve, reject) => {
- cy.get('#patientName').type(patientName);
- setTimeout(() => {
- cy.get('#studyListData')
- .contains(patientName)
- .first()
- .click();
- resolve();
- }, 2000);
- });
- });
+ cy.openStudyList();
+ cy.get('#patientName').type(patientName);
+ cy.wait('@getStudies');
+ cy.get('#studyListData .studylistStudy', { timeout: 5000 })
+ .contains(patientName)
+ .first().click();
});
/**
@@ -82,6 +74,12 @@ Cypress.Commands.add('isPageLoaded', (url = '/viewer/') => {
return cy.location('pathname', { timeout: 60000 }).should('include', url);
});
+Cypress.Commands.add('openStudyList', patientName => {
+ cy.initRouteAliases();
+ cy.visit('/');
+ cy.wait('@getStudies');
+});
+
/**
* Command to perform a drag and drop action. Before using this command, we must get the element that should be dragged first.
* Example of usage: cy.get(element-to-be-dragged).drag(dropzone-element)
diff --git a/platform/viewer/src/googleCloud/DicomStorePickerModal.js b/platform/viewer/src/googleCloud/DicomStorePickerModal.js
index 023a5c842..d7ed14884 100644
--- a/platform/viewer/src/googleCloud/DicomStorePickerModal.js
+++ b/platform/viewer/src/googleCloud/DicomStorePickerModal.js
@@ -22,6 +22,8 @@ class DicomStorePickerModal extends Component {
handleEvent = data => {
const servers = GoogleCloudUtilServers.getServers(data, data.dicomstore);
this.props.setServers(servers);
+ // Force auto close
+ this.props.onClose();
};
render() {
diff --git a/platform/viewer/src/studylist/StudyListWithData.js b/platform/viewer/src/studylist/StudyListWithData.js
index e7bf60681..cce0c0646 100644
--- a/platform/viewer/src/studylist/StudyListWithData.js
+++ b/platform/viewer/src/studylist/StudyListWithData.js
@@ -8,6 +8,7 @@ import { StudyList } from '@ohif/ui';
import ConnectedHeader from '../connectedComponents/ConnectedHeader.js';
import * as RoutesUtil from '../routes/routesUtil';
import moment from 'moment';
+import isEqual from 'lodash.isequal';
import ConnectedDicomFilesUploader from '../googleCloud/ConnectedDicomFilesUploader';
import ConnectedDicomStorePicker from '../googleCloud/ConnectedDicomStorePicker';
import filesToStudies from '../lib/filesToStudies.js';
@@ -20,8 +21,9 @@ import AppContext from '../context/AppContext';
class StudyListWithData extends Component {
static contextType = AppContext;
state = {
- searchData: {},
+ searchOutdated: true,
studies: [],
+ searchingStudies: false,
error: null,
modalComponentId: null,
};
@@ -62,6 +64,7 @@ class StudyListWithData extends Component {
if (!this.props.server && appConfig.enableGoogleCloudAdapter) {
this.setState({
modalComponentId: 'DicomStorePicker',
+ searchOutdated: false,
});
} else {
this.searchForStudies({
@@ -71,21 +74,33 @@ class StudyListWithData extends Component {
}
}
- componentDidUpdate(prevProps) {
- if (!this.state.searchData && !this.state.studies) {
- this.searchForStudies();
- }
- if (this.props.server !== prevProps.server) {
- this.setState({
- modalComponentId: null,
- searchData: null,
- studies: null,
- });
+ componentDidUpdate(prevProps, prevState) {
+ const hasNewServer = !isEqual(this.props.server, prevProps.server);
+
+ const { searchOutdated, searchingStudies } = this.state;
+
+ if (!searchingStudies) {
+ if (hasNewServer) {
+ const { appConfig = {} } = this.context;
+
+ const newState = {
+ searchOutdated: true,
+ studies: null,
+ };
+ if (appConfig.enableGoogleCloudAdapter) {
+ newState.modalComponentId = null;
+ }
+ this.setState(newState);
+ }
+
+ if (searchOutdated) {
+ this.searchForStudies();
+ }
}
}
searchForStudies = (searchData = StudyListWithData.defaultSearchData) => {
- const { server } = this.props;
+ const { server = {} } = this.props;
const filter = {
patientId: searchData.patientId,
patientName: searchData.patientName,
@@ -105,7 +120,9 @@ class StudyListWithData extends Component {
// TODO: add sorting
const promise = OHIF.studies.searchStudies(server, filter);
- // Render the viewer when the data is ready
+ this.setState({
+ searchingStudies: true,
+ });
promise
.then(studies => {
if (!studies) {
@@ -150,11 +167,15 @@ class StudyListWithData extends Component {
this.setState({
studies: sortedStudies,
+ searchingStudies: false,
+ searchOutdated: false,
});
})
.catch(error => {
this.setState({
error: true,
+ searchingStudies: false,
+ searchOutdated: false,
});
throw new Error(error);
@@ -208,8 +229,6 @@ class StudyListWithData extends Component {
if (this.state.error) {
return
Error: {JSON.stringify(this.state.error)}
;
- } else if (this.state.studies === null && !this.state.modalComponentId) {
- return
Loading...
;
}
let healthCareApiButtons = null;
@@ -240,8 +259,9 @@ class StudyListWithData extends Component {
const studyList = (
- {this.state.studies ? (
+ {this.state.studies || this.state.searchingStudies ? (