feat: 🎸 Load spinner when selecting gcloud store. Add key on td (#1034)
* feat: 🎸 Load spinner when selecting gcloud store. Add key on td * feat: 🎸 Code review. Translate loading study status * feat: 🎸 Code review. Minor code refactoring * fix: add missing study and index declerations * test: Improviment on VTK beforeEach hook (#1057) * feat: 🎸 Some improvements on table cell and react lifecycle * feat: 🎸 Prevent component update on a not searchData changing * feat: 🎸 Some cypress improv to pass ci * feat: 🎸 Code reviewe and also fixing list for gcloud * feat: 🎸 Code review. Add spinner on first load of store * feat: 🎸 Code review. Centering loading list spinner icon
This commit is contained in:
parent
dea0ceab57
commit
e62f403fe9
@ -11,11 +11,79 @@ import { StudylistToolbar } from './StudyListToolbar.js';
|
|||||||
import { isInclusivelyBeforeDay } from 'react-dates';
|
import { isInclusivelyBeforeDay } from 'react-dates';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
|
import isEqual from 'lodash.isequal';
|
||||||
import { withTranslation } from '../../utils/LanguageProvider';
|
import { withTranslation } from '../../utils/LanguageProvider';
|
||||||
|
|
||||||
const today = moment();
|
const today = moment();
|
||||||
const lastWeek = moment().subtract(7, 'day');
|
const lastWeek = moment().subtract(7, 'day');
|
||||||
const lastMonth = moment().subtract(1, 'month');
|
const lastMonth = moment().subtract(1, 'month');
|
||||||
|
function getPaginationFragment(
|
||||||
|
props,
|
||||||
|
searchData,
|
||||||
|
nextPageCb,
|
||||||
|
prevPageCb,
|
||||||
|
changeRowsPerPageCb
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<PaginationArea
|
||||||
|
pageOptions={props.pageOptions}
|
||||||
|
currentPage={searchData.currentPage}
|
||||||
|
nextPageFunc={nextPageCb}
|
||||||
|
prevPageFunc={prevPageCb}
|
||||||
|
onRowsPerPageChange={changeRowsPerPageCb}
|
||||||
|
rowsPerPage={searchData.rowsPerPage}
|
||||||
|
recordCount={props.studies.length}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className="loading">
|
||||||
|
<StudyListLoadingText />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (error) {
|
||||||
|
return (
|
||||||
|
<div className="notFound">
|
||||||
|
{translate('There was an error fetching studies')}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (!studies.length) {
|
||||||
|
return <div className="notFound">{translate('No matching results')}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class StudyList extends Component {
|
class StudyList extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -111,24 +179,27 @@ class StudyList extends Component {
|
|||||||
getBlurHandler(key) {
|
getBlurHandler(key) {
|
||||||
return event => {
|
return event => {
|
||||||
this.delayedSearch.cancel();
|
this.delayedSearch.cancel();
|
||||||
this.setSearchData(key, event.target.value, this.search);
|
this.setSearchData(key, event.target.value);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setSearchData(key, value, callback) {
|
setSearchData(key, value) {
|
||||||
const searchData = this.state.searchData;
|
const searchData = { ...this.state.searchData };
|
||||||
searchData[key] = value;
|
searchData[key] = value;
|
||||||
this.setState({ searchData }, callback);
|
|
||||||
|
if (!isEqual(searchData[key], this.state.searchData[key])) {
|
||||||
|
this.setState({ ...this.state, searchData });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSearchDataBatch(keyValues, callback) {
|
setSearchDataBatch(keyValues) {
|
||||||
const searchData = this.state.searchData;
|
const searchData = { ...this.state.searchData };
|
||||||
|
|
||||||
Object.keys(keyValues).forEach(key => {
|
Object.keys(keyValues).forEach(key => {
|
||||||
searchData[key] = keyValues[key];
|
searchData[key] = keyValues[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState({ searchData }, callback);
|
this.setState({ searchData });
|
||||||
}
|
}
|
||||||
|
|
||||||
async onInputKeydown(event) {
|
async onInputKeydown(event) {
|
||||||
@ -138,7 +209,7 @@ class StudyList extends Component {
|
|||||||
|
|
||||||
this.delayedSearch.cancel();
|
this.delayedSearch.cancel();
|
||||||
// reset the page because user is doing a new search
|
// reset the page because user is doing a new search
|
||||||
this.setSearchData('currentPage', 0, this.search);
|
this.setSearchData('currentPage', 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,45 +225,21 @@ class StudyList extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoMachingResults() {
|
|
||||||
if (!this.props.studies.length && !this.state.error) {
|
|
||||||
return <div className="notFound">No matching results</div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderHasError() {
|
|
||||||
if (this.state.error) {
|
|
||||||
return (
|
|
||||||
<div className="notFound">There was an error fetching studies</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderIsLoading() {
|
|
||||||
if (this.state.loading) {
|
|
||||||
return (
|
|
||||||
<div className="loading">
|
|
||||||
<StudyListLoadingText />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPage(currentPage) {
|
nextPage(currentPage) {
|
||||||
currentPage = currentPage + 1;
|
currentPage = currentPage + 1;
|
||||||
this.delayedSearch.cancel();
|
this.delayedSearch.cancel();
|
||||||
this.setSearchData('currentPage', currentPage, this.search);
|
this.setSearchData('currentPage', currentPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
prevPage(currentPage) {
|
prevPage(currentPage) {
|
||||||
currentPage = currentPage - 1;
|
currentPage = currentPage - 1;
|
||||||
this.delayedSearch.cancel();
|
this.delayedSearch.cancel();
|
||||||
this.setSearchData('currentPage', currentPage, this.search);
|
this.setSearchData('currentPage', currentPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowsPerPageChange(rowsPerPage) {
|
onRowsPerPageChange(rowsPerPage) {
|
||||||
this.delayedSearch.cancel();
|
this.delayedSearch.cancel();
|
||||||
this.setSearchDataBatch({ rowsPerPage, currentPage: 0 }, this.search);
|
this.setSearchDataBatch({ rowsPerPage, currentPage: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
onSortClick(field) {
|
onSortClick(field) {
|
||||||
@ -213,7 +260,7 @@ class StudyList extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.delayedSearch.cancel();
|
this.delayedSearch.cancel();
|
||||||
this.setSearchData('sortData', { field, order }, this.search);
|
this.setSearchData('sortData', { field, order });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,10 +268,39 @@ class StudyList extends Component {
|
|||||||
this.setState({ highlightedItem: studyItemUid });
|
this.setState({ highlightedItem: studyItemUid });
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTableRow(study) {
|
getTableRow(study, index) {
|
||||||
|
const trKey = `trStudy${index}${study.studyInstanceUid}`;
|
||||||
|
|
||||||
|
if (!study) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTableCell = (
|
||||||
|
study,
|
||||||
|
studyKey,
|
||||||
|
emptyValue = '',
|
||||||
|
emptyClass = ''
|
||||||
|
) => {
|
||||||
|
const componentKey = `td${studyKey}`;
|
||||||
|
const isValidValue = study && typeof study[studyKey] === 'string';
|
||||||
|
let className = emptyClass;
|
||||||
|
let value = emptyValue;
|
||||||
|
|
||||||
|
if (isValidValue) {
|
||||||
|
className = studyKey;
|
||||||
|
value = study[studyKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td key={componentKey} className={className}>
|
||||||
|
{value}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={study.studyInstanceUid}
|
key={trKey}
|
||||||
className={
|
className={
|
||||||
this.state.highlightedItem === study.studyInstanceUid
|
this.state.highlightedItem === study.studyInstanceUid
|
||||||
? 'studylistStudy noselect active'
|
? 'studylistStudy noselect active'
|
||||||
@ -241,47 +317,35 @@ class StudyList extends Component {
|
|||||||
this.props.onSelectItem(study.studyInstanceUid);
|
this.props.onSelectItem(study.studyInstanceUid);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<td className={study.patientName ? 'patientName' : 'emptyCell'}>
|
{getTableCell(
|
||||||
{study.patientName || `(${this.props.t('Empty')})`}
|
study,
|
||||||
</td>
|
'patientName',
|
||||||
|
`(${this.props.t('Empty')})`,
|
||||||
<td className="patientId">{study.patientId}</td>
|
'emptyCell'
|
||||||
<td className="accessionNumber">{study.accessionNumber}</td>
|
)}
|
||||||
<td className="studyDate">{study.studyDate}</td>
|
{getTableCell(study, 'patientId')}
|
||||||
<td className="modalities">{study.modalities}</td>
|
{getTableCell(study, 'accessionNumber')}
|
||||||
<td className="studyDescription">{study.studyDescription}</td>
|
{getTableCell(study, 'studyDate')}
|
||||||
|
{getTableCell(study, 'modalities')}
|
||||||
|
{getTableCell(study, 'studyDescription')}
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(previousProps, previousState) {
|
||||||
|
if (!isEqual(previousState.searchData, this.state.searchData)) {
|
||||||
|
this.search();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTableBody(noListFragment) {
|
||||||
|
return !noListFragment && this.props.studies
|
||||||
|
? this.props.studies.map(this.getTableRow.bind(this))
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const tableMeta = {
|
const tableMeta = getTableMeta(this.props.t);
|
||||||
patientName: {
|
|
||||||
displayText: this.props.t('PatientName'),
|
|
||||||
sort: 0,
|
|
||||||
},
|
|
||||||
patientId: {
|
|
||||||
displayText: this.props.t('MRN'),
|
|
||||||
sort: 0,
|
|
||||||
},
|
|
||||||
accessionNumber: {
|
|
||||||
displayText: this.props.t('AccessionNumber'),
|
|
||||||
sort: 0,
|
|
||||||
},
|
|
||||||
studyDate: {
|
|
||||||
displayText: this.props.t('StudyDate'),
|
|
||||||
inputType: 'date-range',
|
|
||||||
sort: 0,
|
|
||||||
},
|
|
||||||
modalities: {
|
|
||||||
displayText: this.props.t('Modality'),
|
|
||||||
sort: 0,
|
|
||||||
},
|
|
||||||
studyDescription: {
|
|
||||||
displayText: this.props.t('StudyDescription'),
|
|
||||||
sort: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply sort
|
// Apply sort
|
||||||
const sortedFieldName = this.state.searchData.sortData.field;
|
const sortedFieldName = this.state.searchData.sortData.field;
|
||||||
@ -294,14 +358,20 @@ class StudyList extends Component {
|
|||||||
|
|
||||||
// Sort Icons
|
// Sort Icons
|
||||||
const sortIcons = ['sort', 'sort-up', 'sort-down'];
|
const sortIcons = ['sort', 'sort-up', 'sort-down'];
|
||||||
|
const noListFragment = getNoListFragment(
|
||||||
|
this.props.t,
|
||||||
|
this.props.studies,
|
||||||
|
this.state.error,
|
||||||
|
this.props.loading || this.state.loading
|
||||||
|
);
|
||||||
|
const tableBody = this.renderTableBody(noListFragment);
|
||||||
|
const studiesNum = (this.props.studies && this.props.studies.length) || 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="StudyList">
|
<div className="StudyList">
|
||||||
<div className="studyListToolbar clearfix">
|
<div className="studyListToolbar clearfix">
|
||||||
<div className="header pull-left">{this.props.t('StudyList')}</div>
|
<div className="header pull-left">{this.props.t('StudyList')}</div>
|
||||||
<div className="studyCount pull-right">
|
<div className="studyCount pull-right">{studiesNum}</div>
|
||||||
{this.props.studies.length}
|
|
||||||
</div>
|
|
||||||
<div className="pull-right">
|
<div className="pull-right">
|
||||||
{this.props.studyListFunctionsEnabled ? (
|
{this.props.studyListFunctionsEnabled ? (
|
||||||
<StudylistToolbar onImport={this.props.onImport} />
|
<StudylistToolbar onImport={this.props.onImport} />
|
||||||
@ -367,22 +437,16 @@ class StudyList extends Component {
|
|||||||
(this.state.focusedInput === 'endDate' ||
|
(this.state.focusedInput === 'endDate' ||
|
||||||
preset)
|
preset)
|
||||||
) {
|
) {
|
||||||
this.setSearchDataBatch(
|
this.setSearchDataBatch({
|
||||||
{
|
studyDateFrom: startDate.toDate(),
|
||||||
studyDateFrom: startDate.toDate(),
|
studyDateTo: endDate.toDate(),
|
||||||
studyDateTo: endDate.toDate(),
|
});
|
||||||
},
|
|
||||||
this.search
|
|
||||||
);
|
|
||||||
this.setState({ focusedInput: false });
|
this.setState({ focusedInput: false });
|
||||||
} else if (!startDate && !endDate) {
|
} else if (!startDate && !endDate) {
|
||||||
this.setSearchDataBatch(
|
this.setSearchDataBatch({
|
||||||
{
|
studyDateFrom: null,
|
||||||
studyDateFrom: null,
|
studyDateTo: null,
|
||||||
studyDateTo: null,
|
});
|
||||||
},
|
|
||||||
this.search
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
focusedInput={this.state.focusedInput}
|
focusedInput={this.state.focusedInput}
|
||||||
@ -398,26 +462,18 @@ class StudyList extends Component {
|
|||||||
})}
|
})}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="studyListData">
|
<tbody id="studyListData">{tableBody}</tbody>
|
||||||
{this.props.studies.map(study => {
|
|
||||||
return this.renderTableRow(study);
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{this.renderIsLoading()}
|
{noListFragment
|
||||||
{this.renderHasError()}
|
? noListFragment
|
||||||
{this.renderNoMachingResults()}
|
: getPaginationFragment(
|
||||||
|
this.props,
|
||||||
<PaginationArea
|
this.state.searchData,
|
||||||
pageOptions={this.props.pageOptions}
|
this.nextPage,
|
||||||
currentPage={this.state.searchData.currentPage}
|
this.prevPage,
|
||||||
nextPageFunc={this.nextPage}
|
this.onRowsPerPageChange
|
||||||
prevPageFunc={this.prevPage}
|
)}
|
||||||
onRowsPerPageChange={this.onRowsPerPageChange}
|
|
||||||
rowsPerPage={this.state.searchData.rowsPerPage}
|
|
||||||
recordCount={this.props.studies.length}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -82,9 +82,14 @@ placeholder-color(c)
|
|||||||
position: absolute
|
position: absolute
|
||||||
z-index: 2
|
z-index: 2
|
||||||
|
|
||||||
.loading-text
|
.loading
|
||||||
color: var(--table-text-secondary-color)
|
display: flex;
|
||||||
font-size: 30px
|
justify-content: center;
|
||||||
|
|
||||||
|
.loading-text
|
||||||
|
color: var(--table-text-secondary-color)
|
||||||
|
font-size: 30px
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
.notFound
|
.notFound
|
||||||
color: var(--table-text-secondary-color)
|
color: var(--table-text-secondary-color)
|
||||||
|
|||||||
@ -1,12 +1,17 @@
|
|||||||
import { Icon } from './../../elements/Icon';
|
import { Icon } from './../../elements/Icon';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { withTranslation } from '../../utils/LanguageProvider';
|
||||||
|
|
||||||
function StudyListLoadingText() {
|
function StudyListLoadingText({ t: translate }) {
|
||||||
return (
|
return (
|
||||||
<div className="loading-text">
|
<div className="loading-text">
|
||||||
Loading... <Icon name="circle-notch" animation="pulse" />
|
{translate('Loading')}... <Icon name="circle-notch" animation="pulse" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { StudyListLoadingText };
|
const connectedComponent = withTranslation('StudyListLoadingText')(
|
||||||
|
StudyListLoadingText
|
||||||
|
);
|
||||||
|
|
||||||
|
export { connectedComponent as StudyListLoadingText };
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
describe('OHIFStandaloneViewer', () => {
|
describe('OHIFStandaloneViewer', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.visit('/');
|
cy.openStudyList();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loads route with at least 2 rows', () => {
|
it('loads route with at least 2 rows', () => {
|
||||||
|
|||||||
@ -35,8 +35,8 @@ export function initCommonElementsAliases() {
|
|||||||
//Creating aliases for Routes
|
//Creating aliases for Routes
|
||||||
export function initRouteAliases() {
|
export function initRouteAliases() {
|
||||||
cy.server();
|
cy.server();
|
||||||
cy.route('GET', '/**/series/**').as('getStudySeries');
|
cy.route('GET', '**/series**').as('getStudySeries');
|
||||||
cy.route('GET', '/**/studies/**').as('getStudies');
|
cy.route('GET', '**/studies**').as('getStudies');
|
||||||
}
|
}
|
||||||
|
|
||||||
//Creating aliases for VTK tools buttons
|
//Creating aliases for VTK tools buttons
|
||||||
|
|||||||
@ -39,20 +39,12 @@ import {
|
|||||||
* @param {string} PatientName - Patient name that we would like to search for
|
* @param {string} PatientName - Patient name that we would like to search for
|
||||||
*/
|
*/
|
||||||
Cypress.Commands.add('openStudy', patientName => {
|
Cypress.Commands.add('openStudy', patientName => {
|
||||||
cy.initRouteAliases();
|
cy.openStudyList();
|
||||||
cy.visit('/');
|
cy.get('#patientName').type(patientName);
|
||||||
cy.wrap(null).then(() => {
|
cy.wait('@getStudies');
|
||||||
return new Cypress.Promise((resolve, reject) => {
|
cy.get('#studyListData .studylistStudy', { timeout: 5000 })
|
||||||
cy.get('#patientName').type(patientName);
|
.contains(patientName)
|
||||||
setTimeout(() => {
|
.first().click();
|
||||||
cy.get('#studyListData')
|
|
||||||
.contains(patientName)
|
|
||||||
.first()
|
|
||||||
.click();
|
|
||||||
resolve();
|
|
||||||
}, 2000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,6 +74,12 @@ Cypress.Commands.add('isPageLoaded', (url = '/viewer/') => {
|
|||||||
return cy.location('pathname', { timeout: 60000 }).should('include', url);
|
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.
|
* 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)
|
* Example of usage: cy.get(element-to-be-dragged).drag(dropzone-element)
|
||||||
|
|||||||
@ -22,6 +22,8 @@ class DicomStorePickerModal extends Component {
|
|||||||
handleEvent = data => {
|
handleEvent = data => {
|
||||||
const servers = GoogleCloudUtilServers.getServers(data, data.dicomstore);
|
const servers = GoogleCloudUtilServers.getServers(data, data.dicomstore);
|
||||||
this.props.setServers(servers);
|
this.props.setServers(servers);
|
||||||
|
// Force auto close
|
||||||
|
this.props.onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { StudyList } from '@ohif/ui';
|
|||||||
import ConnectedHeader from '../connectedComponents/ConnectedHeader.js';
|
import ConnectedHeader from '../connectedComponents/ConnectedHeader.js';
|
||||||
import * as RoutesUtil from '../routes/routesUtil';
|
import * as RoutesUtil from '../routes/routesUtil';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import isEqual from 'lodash.isequal';
|
||||||
import ConnectedDicomFilesUploader from '../googleCloud/ConnectedDicomFilesUploader';
|
import ConnectedDicomFilesUploader from '../googleCloud/ConnectedDicomFilesUploader';
|
||||||
import ConnectedDicomStorePicker from '../googleCloud/ConnectedDicomStorePicker';
|
import ConnectedDicomStorePicker from '../googleCloud/ConnectedDicomStorePicker';
|
||||||
import filesToStudies from '../lib/filesToStudies.js';
|
import filesToStudies from '../lib/filesToStudies.js';
|
||||||
@ -20,8 +21,9 @@ import AppContext from '../context/AppContext';
|
|||||||
class StudyListWithData extends Component {
|
class StudyListWithData extends Component {
|
||||||
static contextType = AppContext;
|
static contextType = AppContext;
|
||||||
state = {
|
state = {
|
||||||
searchData: {},
|
searchOutdated: true,
|
||||||
studies: [],
|
studies: [],
|
||||||
|
searchingStudies: false,
|
||||||
error: null,
|
error: null,
|
||||||
modalComponentId: null,
|
modalComponentId: null,
|
||||||
};
|
};
|
||||||
@ -62,6 +64,7 @@ class StudyListWithData extends Component {
|
|||||||
if (!this.props.server && appConfig.enableGoogleCloudAdapter) {
|
if (!this.props.server && appConfig.enableGoogleCloudAdapter) {
|
||||||
this.setState({
|
this.setState({
|
||||||
modalComponentId: 'DicomStorePicker',
|
modalComponentId: 'DicomStorePicker',
|
||||||
|
searchOutdated: false,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.searchForStudies({
|
this.searchForStudies({
|
||||||
@ -71,21 +74,33 @@ class StudyListWithData extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (!this.state.searchData && !this.state.studies) {
|
const hasNewServer = !isEqual(this.props.server, prevProps.server);
|
||||||
this.searchForStudies();
|
|
||||||
}
|
const { searchOutdated, searchingStudies } = this.state;
|
||||||
if (this.props.server !== prevProps.server) {
|
|
||||||
this.setState({
|
if (!searchingStudies) {
|
||||||
modalComponentId: null,
|
if (hasNewServer) {
|
||||||
searchData: null,
|
const { appConfig = {} } = this.context;
|
||||||
studies: null,
|
|
||||||
});
|
const newState = {
|
||||||
|
searchOutdated: true,
|
||||||
|
studies: null,
|
||||||
|
};
|
||||||
|
if (appConfig.enableGoogleCloudAdapter) {
|
||||||
|
newState.modalComponentId = null;
|
||||||
|
}
|
||||||
|
this.setState(newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchOutdated) {
|
||||||
|
this.searchForStudies();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
searchForStudies = (searchData = StudyListWithData.defaultSearchData) => {
|
searchForStudies = (searchData = StudyListWithData.defaultSearchData) => {
|
||||||
const { server } = this.props;
|
const { server = {} } = this.props;
|
||||||
const filter = {
|
const filter = {
|
||||||
patientId: searchData.patientId,
|
patientId: searchData.patientId,
|
||||||
patientName: searchData.patientName,
|
patientName: searchData.patientName,
|
||||||
@ -105,7 +120,9 @@ class StudyListWithData extends Component {
|
|||||||
// TODO: add sorting
|
// TODO: add sorting
|
||||||
const promise = OHIF.studies.searchStudies(server, filter);
|
const promise = OHIF.studies.searchStudies(server, filter);
|
||||||
|
|
||||||
// Render the viewer when the data is ready
|
this.setState({
|
||||||
|
searchingStudies: true,
|
||||||
|
});
|
||||||
promise
|
promise
|
||||||
.then(studies => {
|
.then(studies => {
|
||||||
if (!studies) {
|
if (!studies) {
|
||||||
@ -150,11 +167,15 @@ class StudyListWithData extends Component {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
studies: sortedStudies,
|
studies: sortedStudies,
|
||||||
|
searchingStudies: false,
|
||||||
|
searchOutdated: false,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setState({
|
this.setState({
|
||||||
error: true,
|
error: true,
|
||||||
|
searchingStudies: false,
|
||||||
|
searchOutdated: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
@ -208,8 +229,6 @@ class StudyListWithData extends Component {
|
|||||||
|
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
return <div>Error: {JSON.stringify(this.state.error)}</div>;
|
return <div>Error: {JSON.stringify(this.state.error)}</div>;
|
||||||
} else if (this.state.studies === null && !this.state.modalComponentId) {
|
|
||||||
return <div>Loading...</div>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let healthCareApiButtons = null;
|
let healthCareApiButtons = null;
|
||||||
@ -240,8 +259,9 @@ class StudyListWithData extends Component {
|
|||||||
|
|
||||||
const studyList = (
|
const studyList = (
|
||||||
<div className="paginationArea">
|
<div className="paginationArea">
|
||||||
{this.state.studies ? (
|
{this.state.studies || this.state.searchingStudies ? (
|
||||||
<StudyList
|
<StudyList
|
||||||
|
loading={this.state.searchingStudies}
|
||||||
studies={this.state.studies}
|
studies={this.state.studies}
|
||||||
studyListFunctionsEnabled={this.props.studyListFunctionsEnabled}
|
studyListFunctionsEnabled={this.props.studyListFunctionsEnabled}
|
||||||
onImport={this.onImport}
|
onImport={this.onImport}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user