* Add scoord3d parse / display tool to v2 * Update measurement panel with sr measurements * Update measurement panel to display read only items * Cleanup debugger statement * Check for empty measurement * fix SCOORD3D coordinates * Update getRenderableData.js * fix scoord3d coordinate transformation * implement logic to detect the ReferencedSOPInstanceUID if missing in the measurement. Fix also world to IJ coordinates. * Fix broken unit test / import * fix comment style * Init tools only once * restore default config dcmjs server Co-authored-by: igoroctaviano <igoroctaviano@gmail.com>
218 lines
6.2 KiB
JavaScript
218 lines
6.2 KiB
JavaScript
import './MeasurementTable.styl';
|
|
|
|
import React, { Component } from 'react';
|
|
import { withTranslation } from '../../contextProviders';
|
|
|
|
import { Icon } from './../../elements/Icon';
|
|
import { MeasurementTableItem } from './MeasurementTableItem.js';
|
|
import { OverlayTrigger } from './../overlayTrigger';
|
|
import PropTypes from 'prop-types';
|
|
import { ScrollableArea } from './../../ScrollableArea/ScrollableArea.js';
|
|
import { TableList } from './../tableList';
|
|
import { Tooltip } from './../tooltip';
|
|
|
|
class MeasurementTable extends Component {
|
|
static propTypes = {
|
|
measurementCollection: PropTypes.array.isRequired,
|
|
timepoints: PropTypes.array.isRequired,
|
|
overallWarnings: PropTypes.object.isRequired,
|
|
readOnly: PropTypes.bool,
|
|
onItemClick: PropTypes.func,
|
|
onRelabelClick: PropTypes.func,
|
|
onDeleteClick: PropTypes.func,
|
|
onEditDescriptionClick: PropTypes.func,
|
|
selectedMeasurementNumber: PropTypes.number,
|
|
t: PropTypes.func,
|
|
saveFunction: PropTypes.func,
|
|
onSaveComplete: PropTypes.func,
|
|
};
|
|
|
|
static defaultProps = {
|
|
overallWarnings: {
|
|
warningList: [],
|
|
},
|
|
readOnly: false,
|
|
};
|
|
|
|
state = {
|
|
selectedKey: null,
|
|
};
|
|
|
|
render() {
|
|
const { overallWarnings, saveFunction, t } = this.props;
|
|
const hasOverallWarnings = overallWarnings.warningList.length > 0;
|
|
|
|
return (
|
|
<div className="measurementTable">
|
|
<div className="measurementTableHeader">
|
|
{hasOverallWarnings && (
|
|
<OverlayTrigger
|
|
key={'overwall-warning'}
|
|
placement="left"
|
|
overlay={
|
|
<Tooltip
|
|
placement="left"
|
|
className="in tooltip-warning"
|
|
id="tooltip-left"
|
|
style={{}}
|
|
>
|
|
<div className="warningTitle">
|
|
{t('Criteria nonconformities')}
|
|
</div>
|
|
<div className="warningContent">
|
|
{this.getWarningContent()}
|
|
</div>
|
|
</Tooltip>
|
|
}
|
|
>
|
|
<span className="warning-status">
|
|
<span className="warning-border">
|
|
<Icon name="exclamation-triangle" />
|
|
</span>
|
|
</span>
|
|
</OverlayTrigger>
|
|
)}
|
|
{this.getTimepointsHeader()}
|
|
</div>
|
|
<ScrollableArea>
|
|
<div>{this.getMeasurementsGroups()}</div>
|
|
</ScrollableArea>
|
|
<div className="measurementTableFooter">
|
|
{saveFunction && (
|
|
<button
|
|
onClick={this.saveFunction}
|
|
className="saveBtn"
|
|
data-cy="save-measurements-btn"
|
|
>
|
|
<Icon name="save" width="14px" height="14px" />
|
|
Save measurements
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
saveFunction = async event => {
|
|
const { saveFunction, onSaveComplete } = this.props;
|
|
if (saveFunction) {
|
|
try {
|
|
const result = await saveFunction();
|
|
if (onSaveComplete) {
|
|
onSaveComplete({
|
|
title: 'STOW SR',
|
|
message: result.message,
|
|
type: 'success',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
if (onSaveComplete) {
|
|
onSaveComplete({
|
|
title: 'STOW SR',
|
|
message: error.message,
|
|
type: 'error',
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
getMeasurementsGroups = () => {
|
|
return this.props.measurementCollection.map((measureGroup, index) => {
|
|
return (
|
|
<TableList
|
|
key={index}
|
|
customHeader={this.getCustomHeader(measureGroup)}
|
|
>
|
|
{this.getMeasurements(measureGroup)}
|
|
</TableList>
|
|
);
|
|
});
|
|
};
|
|
|
|
getMeasurements = measureGroup => {
|
|
const selectedKey = this.props.selectedMeasurementNumber
|
|
? this.props.selectedMeasurementNumber
|
|
: this.state.selectedKey;
|
|
return measureGroup.measurements.map((measurement, index) => {
|
|
const key = measurement.measurementNumber;
|
|
const itemIndex = measurement.itemNumber || index + 1;
|
|
const itemClass =
|
|
selectedKey === key && !this.props.readOnly ? 'selected' : '';
|
|
return (
|
|
<MeasurementTableItem
|
|
key={key}
|
|
itemIndex={itemIndex}
|
|
itemClass={itemClass}
|
|
measurementData={measurement}
|
|
onItemClick={this.onItemClick}
|
|
onRelabel={this.props.onRelabelClick}
|
|
onDelete={this.props.onDeleteClick}
|
|
onEditDescription={this.props.onEditDescriptionClick}
|
|
/>
|
|
);
|
|
});
|
|
};
|
|
|
|
onItemClick = (event, measurementData) => {
|
|
if (this.props.readOnly) return;
|
|
|
|
this.setState({
|
|
selectedKey: measurementData.measurementNumber,
|
|
});
|
|
|
|
if (this.props.onItemClick) {
|
|
this.props.onItemClick(event, measurementData);
|
|
}
|
|
};
|
|
|
|
getCustomHeader = measureGroup => {
|
|
return (
|
|
<React.Fragment>
|
|
<div className="tableListHeaderTitle">
|
|
{this.props.t(measureGroup.groupName)}
|
|
</div>
|
|
{measureGroup.maxMeasurements && (
|
|
<div className="maxMeasurements">
|
|
{this.props.t('MAX')} {measureGroup.maxMeasurements}
|
|
</div>
|
|
)}
|
|
<div className="numberOfItems">{measureGroup.measurements.length}</div>
|
|
</React.Fragment>
|
|
);
|
|
};
|
|
|
|
getTimepointsHeader = () => {
|
|
const { timepoints, t } = this.props;
|
|
|
|
return timepoints.map((timepoint, index) => {
|
|
return (
|
|
<div key={index} className="measurementTableHeaderItem">
|
|
<div className="timepointLabel">{t(timepoint.key)}</div>
|
|
<div className="timepointDate">{timepoint.date}</div>
|
|
</div>
|
|
);
|
|
});
|
|
};
|
|
|
|
getWarningContent = () => {
|
|
const { warningList = '' } = this.props.overallWarnings;
|
|
|
|
if (Array.isArray(warningList)) {
|
|
const listedWarnings = warningList.map((warn, index) => {
|
|
return <li key={index}>{warn}</li>;
|
|
});
|
|
|
|
return <ol>{listedWarnings}</ol>;
|
|
} else {
|
|
return <React.Fragment>{warningList}</React.Fragment>;
|
|
}
|
|
};
|
|
}
|
|
|
|
const connectedComponent = withTranslation(['MeasurementTable', 'Common'])(
|
|
MeasurementTable
|
|
);
|
|
export { connectedComponent as MeasurementTable };
|
|
export default connectedComponent;
|