fix: Set SR viewport as active by interaction (#1118)

* fix: Set SR viewport as active by interaction

* quick fix

* (eslint) add "before" as global variables

* add data-cy

* add data-cy

* create E2E test

* (E2E) create custom command to set layout size

* remove .only e2e

* remove throttle for onScroll
This commit is contained in:
Rodrigo Antinarelli 2019-10-29 15:21:56 -03:00 committed by Danny Brown
parent 20bfc829f7
commit 5b334175c3
6 changed files with 112 additions and 19 deletions

View File

@ -16,6 +16,7 @@
}, },
"globals": { "globals": {
"cy": true, "cy": true,
"before": true,
"context": true, "context": true,
"Cypress": true, "Cypress": true,
"assert": true "assert": true

View File

@ -0,0 +1,33 @@
import OHIF from '@ohif/core';
import { connect } from 'react-redux';
import DicomHtmlViewport from './DicomHtmlViewport';
const { setViewportActive } = OHIF.redux.actions;
const mapStateToProps = (state, ownProps) => {
const { viewportIndex, byteArray } = ownProps;
const activeViewportIndex = state.viewports;
return {
viewportIndex,
activeViewportIndex,
byteArray,
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
const { viewportIndex } = ownProps;
return {
setViewportActive: () => {
dispatch(setViewportActive(viewportIndex));
},
};
};
const ConnectedDicomHtmlViewport = connect(
mapStateToProps,
mapDispatchToProps
)(DicomHtmlViewport);
export default ConnectedDicomHtmlViewport;

View File

@ -1,6 +1,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types';
import * as dcmjs from 'dcmjs'; import * as dcmjs from 'dcmjs';
import TypedArrayProp from './TypedArrayProp'; import TypedArrayProp from './TypedArrayProp';
import './DicomHtmlViewport.css'; import './DicomHtmlViewport.css';
function getRelationshipString(data) { function getRelationshipString(data) {
@ -30,7 +32,7 @@ function getValueString(data) {
const { const {
CodeMeaning, CodeMeaning,
CodeValue, CodeValue,
CodingSchemeDesignator CodingSchemeDesignator,
} = data.ConceptNameCodeSequence; } = data.ConceptNameCodeSequence;
return `${CodeMeaning} (${CodeValue}, ${CodingSchemeDesignator})`; return `${CodeMeaning} (${CodeValue}, ${CodingSchemeDesignator})`;
@ -75,7 +77,7 @@ function constructContentSequence(data, header) {
} }
const result = { const result = {
items items,
}; };
if (header) { if (header) {
@ -106,9 +108,7 @@ const { DicomMetaDictionary, DicomMessage } = dcmjs.data;
function getMainData(data) { function getMainData(data) {
const root = []; const root = [];
const patientValue = `${data.PatientName} (${data.PatientSex}, #${ const patientValue = `${data.PatientName} (${data.PatientSex}, #${data.PatientID})`;
data.PatientID
})`;
root.push(getMainDataItem('Patient', patientValue)); root.push(getMainDataItem('Patient', patientValue));
const studyValue = data.StudyDescription; const studyValue = data.StudyDescription;
@ -117,15 +117,13 @@ function getMainData(data) {
const seriesValue = `${data.SeriesDescription} (#${data.SeriesNumber})`; const seriesValue = `${data.SeriesDescription} (#${data.SeriesNumber})`;
root.push(getMainDataItem('Series', seriesValue)); root.push(getMainDataItem('Series', seriesValue));
const manufacturerValue = `${data.Manufacturer} (${ const manufacturerValue = `${data.Manufacturer} (${data.ManufacturerModelName}, #${data.DeviceSerialNumber})`;
data.ManufacturerModelName
}, #${data.DeviceSerialNumber})`;
root.push(getMainDataItem('Manufacturer', manufacturerValue)); root.push(getMainDataItem('Manufacturer', manufacturerValue));
const mainDataObjects = { const mainDataObjects = {
CompletionFlag: 'Completion flag', CompletionFlag: 'Completion flag',
VerificationFlag: 'Verification flag' VerificationFlag: 'Verification flag',
}; };
Object.keys(mainDataObjects).forEach(key => { Object.keys(mainDataObjects).forEach(key => {
@ -154,7 +152,7 @@ const getContentSequence = (data, level = 1) => {
const { const {
CodeMeaning, CodeMeaning,
CodeValue, CodeValue,
CodingSchemeDesignator CodingSchemeDesignator,
} = data.ConceptNameCodeSequence; } = data.ConceptNameCodeSequence;
header = `${CodeMeaning} (${CodeValue} - ${CodingSchemeDesignator})`; header = `${CodeMeaning} (${CodeValue} - ${CodingSchemeDesignator})`;
@ -198,11 +196,14 @@ function getMainDataItem(key, value) {
class DicomHtmlViewport extends Component { class DicomHtmlViewport extends Component {
state = { state = {
content: null, content: null,
error: null error: null,
}; };
static propTypes = { static propTypes = {
byteArray: TypedArrayProp.uint8 byteArray: TypedArrayProp.uint8,
setViewportActive: PropTypes.func.isRequired,
viewportIndex: PropTypes.number.isRequired,
activeViewportIndex: PropTypes.number.isRequired,
}; };
componentDidMount() { componentDidMount() {
@ -225,15 +226,34 @@ class DicomHtmlViewport extends Component {
); );
this.setState({ this.setState({
content content,
}); });
} }
setViewportActiveHandler = () => {
const {
setViewportActive,
viewportIndex,
activeViewportIndex,
} = this.props;
if (viewportIndex !== activeViewportIndex) {
setViewportActive();
}
};
render() { render() {
const { content, error } = this.state;
return ( return (
<div className={'DicomHtmlViewport'}> <div
{this.state.content} data-cy="dicom-html-viewport"
{this.state.error && <h2>{JSON.stringify(this.state.error)}</h2>} className="DicomHtmlViewport"
onClick={this.setViewportActiveHandler}
onScroll={this.setViewportActiveHandler}
>
{content}
{error && <h2>{JSON.stringify(error)}</h2>}
</div> </div>
); );
} }

View File

@ -1,7 +1,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import DicomHtmlViewport from './DicomHtmlViewport';
import OHIF from '@ohif/core'; import OHIF from '@ohif/core';
import ConnectedDicomHtmlViewport from './ConnectedDicomHtmlViewport';
const { DicomLoaderService } = OHIF.utils; const { DicomLoaderService } = OHIF.utils;
class OHIFDicomHtmlViewport extends Component { class OHIFDicomHtmlViewport extends Component {
@ -9,6 +10,7 @@ class OHIFDicomHtmlViewport extends Component {
studies: PropTypes.object, studies: PropTypes.object,
displaySet: PropTypes.object, displaySet: PropTypes.object,
viewportIndex: PropTypes.number, viewportIndex: PropTypes.number,
viewportData: PropTypes.object,
}; };
state = { state = {
@ -40,7 +42,10 @@ class OHIFDicomHtmlViewport extends Component {
return ( return (
<> <>
{this.state.byteArray && ( {this.state.byteArray && (
<DicomHtmlViewport byteArray={this.state.byteArray} /> <ConnectedDicomHtmlViewport
byteArray={this.state.byteArray}
viewportIndex={this.props.viewportIndex}
/>
)} )}
{this.state.error && <h2>{JSON.stringify(this.state.error)}</h2>} {this.state.error && <h2>{JSON.stringify(this.state.error)}</h2>}
</> </>

View File

@ -22,4 +22,23 @@ describe('OHIF HTML Extension', () => {
'Imaging Measurement Report' 'Imaging Measurement Report'
); );
}); });
it('checks if the HTML viewport has been set to active by interaction', () => {
cy.setLayout('3', '3');
// check if viewport has been set as active by CLICKING
cy.get('[data-cy=viewprt-grid] > :nth-child(4)')
.click()
.then($viewport => {
cy.wrap($viewport).should('have.class', 'active');
});
// check if viewport has been set as active by SCROLLING
cy.get('[data-cy=viewprt-grid] > :nth-child(7)').then($viewport => {
cy.wrap($viewport)
.find('[data-cy=dicom-html-viewport]')
.scrollTo('bottom');
cy.wrap($viewport).should('have.class', 'active');
});
});
}); });

View File

@ -328,6 +328,21 @@ Cypress.Commands.add('percyCanvasSnapshot', (name, options = {}) => {
}); });
}); });
Cypress.Commands.add('setLayout', (columns = 1, rows = 1) => {
cy.get('.toolbar-button-label')
.contains('Layout')
.click();
cy.get('.layoutChooser')
.find('tr')
.eq(rows - 1)
.find('td')
.eq(columns - 1)
.click();
cy.wait(1000);
});
function convertCanvas(documentClone) { function convertCanvas(documentClone) {
documentClone documentClone
.querySelectorAll('canvas') .querySelectorAll('canvas')
@ -364,4 +379,4 @@ function canvasToImage(selectorOrEl) {
canvas.setAttribute('data-percy-canvas', true); canvas.setAttribute('data-percy-canvas', true);
canvas.parentElement.appendChild(image); canvas.parentElement.appendChild(image);
canvas.style = 'display: none'; canvas.style = 'display: none';
} }