Finishing case progress and save behavior
This commit is contained in:
parent
abe7691730
commit
45a3cdeaf5
@ -7,9 +7,6 @@
|
|||||||
|
|
||||||
{{>toolbarSectionTools toolbarButtons=toolbarButtons}}
|
{{>toolbarSectionTools toolbarButtons=toolbarButtons}}
|
||||||
|
|
||||||
<div id="toolbarSectionEntry" class="toolbarSectionEntry pull-right rm-l-1 p-x-1">
|
|
||||||
{{>caseProgress}}
|
|
||||||
</div>
|
|
||||||
<div id="toggleMeasurements" class="pull-right m-t-1 rm-x-1">
|
<div id="toggleMeasurements" class="pull-right m-t-1 rm-x-1">
|
||||||
{{>roundedButtonGroup rightSidebarToggleButtonData}}
|
{{>roundedButtonGroup rightSidebarToggleButtonData}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -33,38 +33,21 @@ Meteor.startup(() => {
|
|||||||
id: 'linkStackScroll',
|
id: 'linkStackScroll',
|
||||||
name: 'Link',
|
name: 'Link',
|
||||||
action: OHIF.viewerbase.viewportUtils.linkStackScroll
|
action: OHIF.viewerbase.viewportUtils.linkStackScroll
|
||||||
|
}, {
|
||||||
|
id: 'saveMeasurements',
|
||||||
|
name: 'Save measurements',
|
||||||
|
hotkey: 'CTRL+S',
|
||||||
|
action() {
|
||||||
|
const activeTimepoint = OHIF.measurements.getActiveTimepoint();
|
||||||
|
if (!activeTimepoint) return;
|
||||||
|
OHIF.measurements.saveMeasurements(OHIF.viewer.measurementApi, activeTimepoint.timepointId);
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
customCommands.forEach(command => {
|
customCommands.forEach(command => {
|
||||||
_.defaults(OHIF.hotkeys.defaults[contextName], { [command.id]: '' });
|
_.defaults(OHIF.hotkeys.defaults[contextName], { [command.id]: command.hotkey || '' });
|
||||||
OHIF.commands.register(contextName, command.id, {
|
OHIF.commands.register(contextName, command.id, {
|
||||||
name: command.name,
|
name: command.name,
|
||||||
action: command.action || (() => toolManager.setActiveTool(command.id))
|
action: command.action || (() => toolManager.setActiveTool(command.id))
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the save command
|
|
||||||
OHIF.commands.register(contextName, 'storeMeasurements', () => {
|
|
||||||
// Register the hotkey default
|
|
||||||
_.defaults(OHIF.hotkeys.defaults[contextName], { storeMeasurements: '' });
|
|
||||||
|
|
||||||
// Clear signaled unsaved changes...
|
|
||||||
const successHandler = () => {
|
|
||||||
OHIF.ui.unsavedChanges.clear(`${instance.path}.*`);
|
|
||||||
instance.saveObserver.changed();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Display the error messages
|
|
||||||
const errorHandler = data => {
|
|
||||||
OHIF.ui.showDialog('dialogInfo', Object.assign({ class: 'themed' }, data));
|
|
||||||
};
|
|
||||||
|
|
||||||
const promise = OHIF.viewer.measurementApi.storeMeasurements();
|
|
||||||
promise.then(successHandler).catch(errorHandler);
|
|
||||||
OHIF.ui.showDialog('dialogLoading', {
|
|
||||||
promise,
|
|
||||||
text: 'Saving measurement data'
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -246,7 +246,7 @@ class MeasurementApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
storeMeasurements() {
|
storeMeasurements(timepointId) {
|
||||||
const storeFn = configuration.dataExchange.store;
|
const storeFn = configuration.dataExchange.store;
|
||||||
if (!_.isFunction(storeFn)) {
|
if (!_.isFunction(storeFn)) {
|
||||||
return;
|
return;
|
||||||
@ -263,7 +263,8 @@ class MeasurementApi {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const timepoints = this.timepointApi.all();
|
const timepointFilter = timepointId ? { timepointId } : {};
|
||||||
|
const timepoints = this.timepointApi.all(timepointFilter);
|
||||||
const timepointIds = timepoints.map(t => t.timepointId);
|
const timepointIds = timepoints.map(t => t.timepointId);
|
||||||
const patientId = timepoints[0].patientId;
|
const patientId = timepoints[0].patientId;
|
||||||
const filter = {
|
const filter = {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ Template.caseProgress.onCreated(() => {
|
|||||||
|
|
||||||
Template.caseProgress.onRendered(() => {
|
Template.caseProgress.onRendered(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
const { timepointApi, measurementApi } = instance.data;
|
const { timepointApi, measurementApi, timepointId } = instance.data;
|
||||||
|
|
||||||
// Stop here if we have no current timepoint ID (and therefore no defined timepointAPI)
|
// Stop here if we have no current timepoint ID (and therefore no defined timepointAPI)
|
||||||
if (!timepointApi) {
|
if (!timepointApi) {
|
||||||
@ -22,8 +22,13 @@ Template.caseProgress.onRendered(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the current and prior timepoints
|
// Get the current and prior timepoints
|
||||||
const current = timepointApi.current();
|
const current = timepointApi.timepoints.findOne({ timepointId });
|
||||||
const prior = timepointApi.prior();
|
const priorFilter = {
|
||||||
|
latestDate: { $lt: current.latestDate },
|
||||||
|
patientId: current.patientId
|
||||||
|
};
|
||||||
|
const priorSorting = { sort: { latestDate: -1 } };
|
||||||
|
const prior = timepointApi.timepoints.findOne(priorFilter, priorSorting);
|
||||||
|
|
||||||
// Stop here if timepoint is locked
|
// Stop here if timepoint is locked
|
||||||
if (current && current.isLocked) {
|
if (current && current.isLocked) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
@import "{ohif:design}/app"
|
@require '{ohif:design}/app'
|
||||||
|
|
||||||
.caseProgress
|
.caseProgress
|
||||||
transition(all 0.3 ease)
|
transition(all 0.3 ease)
|
||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
h5
|
h5
|
||||||
theme('color', '$textPrimaryColor')
|
theme('color', '$textPrimaryColor')
|
||||||
line-height: 46px
|
line-height: 40px
|
||||||
margin: 0
|
margin: 0
|
||||||
font-size: 15px
|
font-size: 15px
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
|
|||||||
@ -1,27 +1,27 @@
|
|||||||
<template name="radialProgressBar">
|
<template name="radialProgressBar">
|
||||||
<div class="radialProgress">
|
<div class="radialProgress">
|
||||||
<svg id="svg"
|
<svg id="svg"
|
||||||
width="46"
|
width="40"
|
||||||
height="46"
|
height="40"
|
||||||
viewPort="0 0 50 50"
|
viewPort="0 0 40 40"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|
||||||
<!-- stroke-dasharray is 2 * PI * radius !-->
|
<!-- stroke-dasharray is 2 * PI * radius !-->
|
||||||
<circle r="21"
|
<circle r="18"
|
||||||
cx="23"
|
cx="20"
|
||||||
cy="23"
|
cy="20"
|
||||||
fill="transparent"
|
fill="transparent"
|
||||||
stroke-dasharray="131.9469"
|
stroke-dasharray="113.097335529232557"
|
||||||
stroke-dashoffset="0">
|
stroke-dashoffset="0">
|
||||||
</circle>
|
</circle>
|
||||||
{{#unless isLocked}}
|
{{#unless isLocked}}
|
||||||
<circle id="bar"
|
<circle id="bar"
|
||||||
r="21"
|
r="18"
|
||||||
cx="23"
|
cx="20"
|
||||||
cy="23"
|
cy="20"
|
||||||
fill="transparent"
|
fill="transparent"
|
||||||
stroke-dasharray="131.9469"
|
stroke-dasharray="113.097335529232557"
|
||||||
style="stroke-dashoffset: {{progressRadius}}px;">
|
style="stroke-dashoffset: {{progressRadius}}px;">
|
||||||
</circle>
|
</circle>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
|
||||||
Template.radialProgressBar.helpers({
|
Template.radialProgressBar.helpers({
|
||||||
progressComplete() {
|
progressComplete() {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
@ -5,9 +7,9 @@ Template.radialProgressBar.helpers({
|
|||||||
},
|
},
|
||||||
|
|
||||||
progressRadius() {
|
progressRadius() {
|
||||||
var radius = 21 * 2 * Math.PI;
|
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
var percentLeft = (100 - instance.data.progressPercent) / 100;
|
const radius = 18 * 2 * Math.PI;
|
||||||
|
const percentLeft = (100 - instance.data.progressPercent) / 100;
|
||||||
return percentLeft * radius;
|
return percentLeft * radius;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
@import "{ohif:design}/app"
|
@require '{ohif:design}/app'
|
||||||
|
|
||||||
$circleSize = 46px
|
$circleSize = 40px
|
||||||
|
|
||||||
.radialProgress
|
.radialProgress
|
||||||
position: relative
|
position: relative
|
||||||
@ -29,6 +29,7 @@ $circleSize = 46px
|
|||||||
line-height: $circleSize
|
line-height: $circleSize
|
||||||
left: 50%
|
left: 50%
|
||||||
position: absolute
|
position: absolute
|
||||||
|
text-align: center
|
||||||
top: 50%
|
top: 50%
|
||||||
transform(translate(-50%, -50%))
|
transform(translate(-50%, -50%))
|
||||||
width: $circleSize
|
width: $circleSize
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
@import "{ohif:design}/app"
|
@require '{ohif:design}/app'
|
||||||
|
|
||||||
#measurementTableContainer
|
#measurementTableContainer
|
||||||
theme('background-color', '$primaryBackgroundColor')
|
theme('background-color', '$primaryBackgroundColor')
|
||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
.measurementTableTimepointHeaderRow
|
.measurementTableTimepointHeaderRow
|
||||||
display: flex
|
display: flex
|
||||||
padding: 2px 2px 0 44px
|
padding: 0 2px 0 44px
|
||||||
position: relative
|
position: relative
|
||||||
|
|
||||||
.warning-status
|
.warning-status
|
||||||
|
|||||||
@ -6,5 +6,8 @@
|
|||||||
<div class="timepointDate">
|
<div class="timepointDate">
|
||||||
{{formatDA latestDate "DD-MMM-YY"}}
|
{{formatDA latestDate "DD-MMM-YY"}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="case-progress-container">
|
||||||
|
{{>caseProgress}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
@import "{ohif:design}/app"
|
@require '{ohif:design}/app'
|
||||||
|
|
||||||
.measurementTableTimepointHeader
|
.measurementTableTimepointHeader
|
||||||
flex: 1
|
flex: 1
|
||||||
justify-content: space-around
|
justify-content: space-around
|
||||||
|
padding-top: 2px
|
||||||
|
position: relative
|
||||||
|
|
||||||
div
|
.timepointName, .timepointDate
|
||||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||||
font-weight: 400
|
font-weight: 400
|
||||||
padding-left: 12px
|
padding-left: 12px
|
||||||
@ -20,3 +22,8 @@
|
|||||||
font-size: 14px
|
font-size: 14px
|
||||||
line-height: 20px
|
line-height: 20px
|
||||||
padding-bottom: 6px
|
padding-bottom: 6px
|
||||||
|
|
||||||
|
.case-progress-container
|
||||||
|
position: absolute
|
||||||
|
right: 4px
|
||||||
|
top: 0
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import './hangingProtocolCustomizations';
|
|||||||
import './MeasurementHandlers';
|
import './MeasurementHandlers';
|
||||||
import './MeasurementManager';
|
import './MeasurementManager';
|
||||||
import './navigateOverLesions';
|
import './navigateOverLesions';
|
||||||
|
import './saveMeasurements';
|
||||||
import './syncMeasurementAndToolData';
|
import './syncMeasurementAndToolData';
|
||||||
import './toggleLabelButton';
|
import './toggleLabelButton';
|
||||||
import './triggerTimepointUnsavedChanges';
|
import './triggerTimepointUnsavedChanges';
|
||||||
|
|||||||
31
Packages/ohif-measurements/client/lib/saveMeasurements.js
Normal file
31
Packages/ohif-measurements/client/lib/saveMeasurements.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
OHIF.measurements.saveMeasurements = (measurementApi, timepointId) => {
|
||||||
|
const { unsavedChanges, notifications, showDialog } = OHIF.ui;
|
||||||
|
const basePath = `viewer.studyViewer.measurements.${timepointId}`;
|
||||||
|
|
||||||
|
// Stop here if there were no changes to the timepoint
|
||||||
|
if (unsavedChanges.probe(basePath) === 0) return;
|
||||||
|
|
||||||
|
// Clear unsaved changes state and display success message
|
||||||
|
const successHandler = () => {
|
||||||
|
unsavedChanges.clear(basePath, true);
|
||||||
|
notifications.success({ text: 'The measurement data was successfully saved' });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Display the error messages
|
||||||
|
const errorHandler = data => {
|
||||||
|
showDialog('dialogInfo', Object.assign({ class: 'themed' }, data));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Call the storage method and display a loading overlay
|
||||||
|
const promise = measurementApi.storeMeasurements(timepointId);
|
||||||
|
promise.then(successHandler).catch(errorHandler);
|
||||||
|
showDialog('dialogLoading', {
|
||||||
|
promise,
|
||||||
|
text: 'Saving measurement data'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return the save promise
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user