From 9403a091d9c12bab30029a5ad52d139eab23d6b2 Mon Sep 17 00:00:00 2001 From: dannyrb Date: Mon, 29 Jun 2020 22:30:39 -0400 Subject: [PATCH] Update measurement tracking workflow to match requirements --- .../TrackedMeasurementsContext.jsx | 48 +++------ .../measurementTrackingMachine.js | 52 +++++---- .../promptBeginTracking.js | 57 ++++++++++ .../promptTrackNewSeries.js | 102 ++++++++++++++++++ .../promptTrackNewStudy.js | 96 +++++++++++++++++ 5 files changed, 300 insertions(+), 55 deletions(-) create mode 100644 extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptBeginTracking.js create mode 100644 extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewSeries.js create mode 100644 extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewStudy.js diff --git a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.jsx b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.jsx index 063995a13..5081deaad 100644 --- a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.jsx +++ b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.jsx @@ -6,6 +6,9 @@ import { machineConfiguration, defaultOptions, } from './measurementTrackingMachine'; +import promptBeginTracking from './promptBeginTracking'; +import promptTrackNewSeries from './promptTrackNewSeries'; +import promptTrackNewStudy from './promptTrackNewStudy'; const TrackedMeasurementsContext = React.createContext(); TrackedMeasurementsContext.displayName = 'TrackedMeasurementsContext'; @@ -19,41 +22,20 @@ function TrackedMeasurementsContextProvider( UIViewportDialogService, { children } ) { - function promptUser(message, ctx, evt) { - const { viewportIndex, StudyInstanceUID, SeriesInstanceUID } = evt; - - return new Promise(function(resolve, reject) { - /** - * TODO: Will have issues if "SeriesInstanceUID" exists in multiple displaySets? - * - * @param {number} result - -1 | 0 | 1 --> deny | cancel | accept - * @return resolve { userResponse: number, StudyInstanceUID: string, SeriesInstanceUID: string } - */ - const handleSubmit = result => { - UIViewportDialogService.hide(); - resolve({ userResponse: result, StudyInstanceUID, SeriesInstanceUID }); - }; - - UIViewportDialogService.show({ - viewportIndex, - type: 'info', - message, - actions: [ - { type: 'cancel', text: 'No', value: 0 }, - { type: 'secondary', text: 'No, do not ask again', value: -1 }, - { type: 'primary', text: 'Yes', value: 1 }, - ], - onSubmit: handleSubmit, - }); - }); - } - - // Set StateMachine behavior for prompts (invoked services) const machineOptions = Object.assign({}, defaultOptions); machineOptions.services = Object.assign({}, machineOptions.services, { - promptBeginTracking: promptUser.bind(null, 'Start tracking?'), - promptTrackNewStudy: promptUser.bind(null, 'New study?'), - promptTrackNewSeries: promptUser.bind(null, 'New series?'), + promptBeginTracking: promptBeginTracking.bind( + null, + UIViewportDialogService + ), + promptTrackNewSeries: promptTrackNewSeries.bind( + null, + UIViewportDialogService + ), + promptTrackNewStudy: promptTrackNewStudy.bind( + null, + UIViewportDialogService + ), }); diff --git a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/measurementTrackingMachine.js b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/measurementTrackingMachine.js index 680fabf49..40ae9cac6 100644 --- a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/measurementTrackingMachine.js +++ b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/measurementTrackingMachine.js @@ -1,5 +1,13 @@ import { assign } from 'xstate'; +const RESPONSE = { + NO_NEVER: -1, + CANCEL: 0, + CREATE_REPORT: 1, + ADD_SERIES: 2, + SET_STUDY_AND_SERIES: 3, +}; + const machineConfiguration = { id: 'measurementTracking', initial: 'idle', @@ -24,11 +32,11 @@ const machineConfiguration = { { target: 'tracking', actions: ['setTrackedStudyAndSeries'], - cond: 'promptAccepted', + cond: 'shouldSetStudyAndSeries', }, { target: 'off', - cond: 'promptDeclined', + cond: 'shouldKillMachine', }, { target: 'idle', @@ -63,15 +71,21 @@ const machineConfiguration = { ], }, }, - promptTrackNewStudy: { + promptTrackNewSeries: { invoke: { - src: 'promptTrackNewStudy', + src: 'promptTrackNewSeries', onDone: [ { target: 'tracking', - actions: ['setTrackedStudyAndSeries'], - cond: 'promptAccepted', + actions: ['addTrackedSeries'], + cond: 'shouldAddSeries', }, + { + target: 'tracking', + actions: ['setTrackedStudyAndSeries'], + cond: 'shouldSetStudyAndSeries', + }, + // CREATE_REPORT && CANCEL { target: 'tracking', }, @@ -81,14 +95,14 @@ const machineConfiguration = { }, }, }, - promptTrackNewSeries: { + promptTrackNewStudy: { invoke: { - src: 'promptTrackNewSeries', + src: 'promptTrackNewStudy', onDone: [ { target: 'tracking', - actions: ['addTrackedSeries'], - cond: 'promptAccepted', + actions: ['setTrackedStudyAndSeries'], + cond: 'shouldSetStudyAndSeries', }, { target: 'tracking', @@ -135,9 +149,12 @@ const defaultOptions = { })), }, guards: { - promptAccepted: (ctx, evt) => evt.data && evt.data.userResponse === 1, - promptCanceled: (ctx, evt) => evt.data && evt.data.userResponse === 0, - promptDeclined: (ctx, evt) => evt.data && evt.data.userResponse === -1, + shouldKillMachine: (ctx, evt) => + evt.data && evt.data.userResponse === RESPONSE.NO_NEVER, + shouldAddSeries: (ctx, evt) => + evt.data && evt.data.userResponse === RESPONSE.ADD_SERIES, + shouldSetStudyAndSeries: (ctx, evt) => + evt.data && evt.data.userResponse === RESPONSE.SET_STUDY_AND_SERIES, // Has more than 1, or SeriesInstanceUID is not in list // --> Post removal would have non-empty trackedSeries array hasRemainingTrackedSeries: (ctx, evt) => @@ -149,13 +166,4 @@ const defaultOptions = { }, }; -// const measurementTrackingMachine = Machine( -// machineConfiguration, -// defaultOptions -// ); -// .transition(state, eventArgument).value -// const service = interpret(measurementTrackingMachine).start(); -// .send(event): nextState -// .state (getter) -// .onTransition(state => { state.vale }) export { defaultOptions, machineConfiguration }; diff --git a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptBeginTracking.js b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptBeginTracking.js new file mode 100644 index 000000000..e1560150c --- /dev/null +++ b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptBeginTracking.js @@ -0,0 +1,57 @@ +const RESPONSE = { + NO_NEVER: -1, + CANCEL: 0, + CREATE_REPORT: 1, + ADD_SERIES: 2, + SET_STUDY_AND_SERIES: 3, +}; + +function promptUser(UIViewportDialogService, ctx, evt) { + const { viewportIndex, StudyInstanceUID, SeriesInstanceUID } = evt; + + return new Promise(async function(resolve, reject) { + let promptResult = await _askTrackMeasurements( + UIViewportDialogService, + viewportIndex + ); + + resolve({ + userResponse: promptResult, + StudyInstanceUID, + SeriesInstanceUID, + }); + }); +} + +function _askTrackMeasurements(UIViewportDialogService, viewportIndex) { + return new Promise(function(resolve, reject) { + const message = 'Track measurements for this series?'; + const actions = [ + { type: 'cancel', text: 'No', value: RESPONSE.CANCEL }, + { + type: 'secondary', + text: 'No, do not ask again', + value: RESPONSE.NO_NEVER, + }, + { + type: 'primary', + text: 'Yes', + value: RESPONSE.SET_STUDY_AND_SERIES, + }, + ]; + const onSubmit = result => { + UIViewportDialogService.hide(); + resolve(result); + }; + + UIViewportDialogService.show({ + viewportIndex, + type: 'info', + message, + actions, + onSubmit, + }); + }); +} + +export default promptUser; diff --git a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewSeries.js b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewSeries.js new file mode 100644 index 000000000..fbbe31c15 --- /dev/null +++ b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewSeries.js @@ -0,0 +1,102 @@ +const RESPONSE = { + NO_NEVER: -1, + CANCEL: 0, + CREATE_REPORT: 1, + ADD_SERIES: 2, + SET_STUDY_AND_SERIES: 3, +}; + +function promptUser(UIViewportDialogService, ctx, evt) { + const { viewportIndex, StudyInstanceUID, SeriesInstanceUID } = evt; + + return new Promise(async function(resolve, reject) { + let promptResult = await _askShouldAddMeasurements( + UIViewportDialogService, + viewportIndex + ); + + if (promptResult === RESPONSE.CREATE_REPORT) { + promptResult = await _askSaveDiscardOrCancel( + UIViewportDialogService, + viewportIndex + ); + } + + // TODO: Hook into @JamesAPetts createReport + if (promptResult === RESPONSE.CREATE_REPORT) { + window.alert('CREATE REPORT'); + } + + resolve({ + userResponse: promptResult, + StudyInstanceUID, + SeriesInstanceUID, + }); + }); +} + +function _askShouldAddMeasurements(UIViewportDialogService, viewportIndex) { + return new Promise(function(resolve, reject) { + const message = + 'Do you want to add this measurement to the existing report?'; + const actions = [ + { type: 'cancel', text: 'Cancel', value: RESPONSE.CANCEL }, + { + type: 'secondary', + text: 'Create new report', + value: RESPONSE.CREATE_REPORT, + }, + { + type: 'primary', + text: 'Add to existing report', + value: RESPONSE.ADD_SERIES, + }, + ]; + const onSubmit = result => { + UIViewportDialogService.hide(); + resolve(result); + }; + + UIViewportDialogService.show({ + viewportIndex, + type: 'info', + message, + actions, + onSubmit, + }); + }); +} + +function _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) { + return new Promise(function(resolve, reject) { + const message = + 'You have existing tracked measurements. What would you like to do with your existing tracked measurements?'; + const actions = [ + { type: 'cancel', text: 'Cancel', value: RESPONSE.CANCEL }, + { + type: 'secondary', + text: 'Save in report', + value: RESPONSE.CREATE_REPORT, + }, + { + type: 'primary', + text: 'Discard', + value: RESPONSE.SET_STUDY_AND_SERIES, + }, + ]; + const onSubmit = result => { + UIViewportDialogService.hide(); + resolve(result); + }; + + UIViewportDialogService.show({ + viewportIndex, + type: 'info', // TODO: warn + message, + actions, + onSubmit, + }); + }); +} + +export default promptUser; diff --git a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewStudy.js b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewStudy.js new file mode 100644 index 000000000..71265b6c4 --- /dev/null +++ b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewStudy.js @@ -0,0 +1,96 @@ +const RESPONSE = { + NO_NEVER: -1, + CANCEL: 0, + CREATE_REPORT: 1, + ADD_SERIES: 2, + SET_STUDY_AND_SERIES: 3, +}; + +function promptUser(UIViewportDialogService, ctx, evt) { + const { viewportIndex, StudyInstanceUID, SeriesInstanceUID } = evt; + + return new Promise(async function(resolve, reject) { + let promptResult = await _askTrackMeasurements( + UIViewportDialogService, + viewportIndex + ); + + if (promptResult === RESPONSE.SET_STUDY_AND_SERIES) { + promptResult = await _askSaveDiscardOrCancel( + UIViewportDialogService, + viewportIndex + ); + } + + // TODO: Hook into @JamesAPetts createReport + if (promptResult === RESPONSE.CREATE_REPORT) { + window.alert('CREATE REPORT'); + } + + resolve({ + userResponse: promptResult, + StudyInstanceUID, + SeriesInstanceUID, + }); + }); +} + +function _askTrackMeasurements(UIViewportDialogService, viewportIndex) { + return new Promise(function(resolve, reject) { + const message = 'Track measurements for this series?'; + const actions = [ + { type: 'cancel', text: 'No', value: RESPONSE.CANCEL }, + { + type: 'primary', + text: 'Yes', + value: RESPONSE.SET_STUDY_AND_SERIES, + }, + ]; + const onSubmit = result => { + UIViewportDialogService.hide(); + resolve(result); + }; + + UIViewportDialogService.show({ + viewportIndex, + type: 'info', + message, + actions, + onSubmit, + }); + }); +} + +function _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) { + return new Promise(function(resolve, reject) { + const message = + 'Measurements cannot span across multiple studies. Do you want to save your tracked measurements?'; + const actions = [ + { type: 'cancel', text: 'Cancel', value: RESPONSE.CANCEL }, + { + type: 'secondary', + text: 'No, discard previosuly tracked series & measurements', + value: RESPONSE.SET_STUDY_AND_SERIES, + }, + { + type: 'primary', + text: 'Yes', + value: RESPONSE.CREATE_REPORT, + }, + ]; + const onSubmit = result => { + UIViewportDialogService.hide(); + resolve(result); + }; + + UIViewportDialogService.show({ + viewportIndex, + type: 'info', // TODO: warn + message, + actions, + onSubmit, + }); + }); +} + +export default promptUser;