simplify stateMachine

This commit is contained in:
dannyrb 2020-06-06 23:35:12 -04:00
parent 00f8d56a4e
commit 2d903d731f
2 changed files with 95 additions and 135 deletions

View File

@ -19,13 +19,15 @@ function TrackedMeasurementsContextProvider(
UIViewportDialogService, UIViewportDialogService,
{ children } { children }
) { ) {
function promptUser() { function promptUser(ctx, evt) {
const { StudyInstanceUID, SeriesInstanceUID } = evt;
// TODO: ... ActiveViewport? Or Study + Series --> Viewport? // TODO: ... ActiveViewport? Or Study + Series --> Viewport?
// Let's just use zero for meow? // Let's just use zero for meow?
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
const handleSubmit = result => { const handleSubmit = result => {
UIViewportDialogService.hide(); UIViewportDialogService.hide();
resolve(result); // evt.data available for event transition
resolve({ userResponse: result, StudyInstanceUID, SeriesInstanceUID });
}; };
UIViewportDialogService.show({ UIViewportDialogService.show({
@ -45,7 +47,9 @@ function TrackedMeasurementsContextProvider(
const machOptions = Object.assign({}, defaultOptions); const machOptions = Object.assign({}, defaultOptions);
// Merge services // Merge services
machOptions.services = Object.assign({}, machOptions.services, { machOptions.services = Object.assign({}, machOptions.services, {
shouldTrackPrompt: promptUser, promptBeginTracking: promptUser,
promptTrackNewStudy: promptUser,
promptTrackNewSeries: promptUser,
}); });
console.log( console.log(

View File

@ -1,124 +1,101 @@
import { Machine, assign } from 'xstate'; import { assign } from 'xstate';
// import { assign } from '@xstate/immer';
const machineConfiguration = { const machineConfiguration = {
id: 'measurementTracking', id: 'measurementTracking',
initial: 'notTracking', initial: 'idle',
context: { context: {
prevTrackedStudy: '',
prevTrackedSeries: [],
trackedStudy: '', trackedStudy: '',
trackedSeries: [], trackedSeries: [],
promptResponse: 0,
}, },
states: { states: {
notTracking: { off: {
type: 'final',
},
idle: {
entry: 'clearContext', entry: 'clearContext',
on: { on: {
TRACK_SERIES: { TRACK_SERIES: 'promptBeginTracking',
target: 'awaitShouldTrackPrompt',
actions: 'trackSeries',
},
}, },
}, },
awaitShouldTrackPrompt: { promptBeginTracking: {
initial: 'prompt', invoke: {
states: { src: 'promptBeginTracking',
prompt: { onDone: [
invoke: { {
id: 'shouldTrackPrompt', target: 'tracking',
src: 'shouldTrackPrompt', actions: ['setTrackedStudyAndSeries'],
onDone: { cond: 'promptAccepted',
target: 'validateResponse',
actions: assign({ promptResponse: (ctx, evt) => evt.data }),
},
onError: {
target: 'validateResponse',
actions: assign({ promptResponse: (ctx, evt) => evt.data }),
},
}, },
}, {
validateResponse: { target: 'off',
on: { cond: 'promptDeclined',
'': [
{
target: '#measurementTracking.tracking',
cond: 'acceptResponse',
},
{
target: '#measurementTracking.neverTrack',
cond: 'rejectResponse',
},
{
target: '#measurementTracking.notTracking',
cond: 'cancelResponse',
},
],
}, },
{
target: 'idle',
},
],
onError: {
target: 'idle',
}, },
}, },
}, },
neverTrack: {
type: 'final',
},
tracking: { tracking: {
on: { on: {
TRACK_SERIES: [ TRACK_SERIES: [
{ {
target: 'tracking', target: 'promptTrackNewStudy',
cond: 'hasNewSeriesForTrackedStudy', cond: 'isNewStudy',
actions: 'trackSeries',
}, },
{ {
target: 'awaitShouldTrackNewStudyPrompt', target: 'promptTrackNewSeries',
cond: 'willTrackNewStudy', cond: 'isNewSeries',
actions: ['setPrevTracked', 'clearTrackedSeries', 'trackSeries'],
}, },
], ],
UNTRACK_SERIES: [ UNTRACK_SERIES: [
{ {
target: 'notTracking', target: 'tracking',
cond: 'willBeEmpty', actions: ['removeTrackedSeries'],
actions: 'untrackSeries', cond: 'hasRemainingTrackedSeries',
}, },
{ {
target: 'tracking', target: 'idle',
actions: 'untrackSeries',
}, },
], ],
}, },
}, },
awaitShouldTrackNewStudyPrompt: { promptTrackNewStudy: {
initial: 'prompt', invoke: {
states: { src: 'promptTrackNewStudy',
prompt: { onDone: [
invoke: { {
id: 'shouldTrackPrompt', target: 'tracking',
src: () => confirmDialog('Should we track new study?'), actions: ['setTrackedStudyAndSeries'],
onDone: { cond: 'promptAccepted',
target: 'validateResponse',
actions: assign({ promptResponse: (ctx, evt) => evt.data }),
},
onError: {
target: 'validateResponse',
actions: assign({ promptResponse: (ctx, evt) => evt.data }),
},
}, },
{
target: 'tracking',
},
],
onError: {
target: 'idle',
}, },
validateResponse: { },
on: { },
'': [ promptTrackNewSeries: {
{ invoke: {
target: '#measurementTracking.tracking', src: 'promptTrackNewSeries',
cond: 'acceptResponse', onDone: [
}, {
{ target: 'tracking',
target: '#measurementTracking.tracking', actions: ['addTrackedSeries'],
cond: 'rejectResponse', cond: 'promptAccepted',
actions: 'restorePrevTracked',
},
],
}, },
{
target: 'tracking',
},
],
onError: {
target: 'idle',
}, },
}, },
}, },
@ -126,68 +103,47 @@ const machineConfiguration = {
strict: true, strict: true,
}; };
function confirmDialog(msg) {
return new Promise(function(resolve, reject) {
let confirmed = window.confirm(msg);
return confirmed ? resolve(1) : reject(-1);
});
}
const defaultOptions = { const defaultOptions = {
services: { services: {
shouldTrackPrompt: () => { promptBeginTracking: (ctx, evt) => {
return confirmDialog('Should we start tracking?'); // return { userResponse, StudyInstanceUID, SeriesInstanceUID }
},
promptTrackNewStudy: (ctx, evt) => {
// return { userResponse, StudyInstanceUID, SeriesInstanceUID }
},
promptTrackNewSeries: (ctx, evt) => {
// return { userResponse, StudyInstanceUID, SeriesInstanceUID }
}, },
}, },
actions: { actions: {
clearContext: assign({ clearContext: assign({
prevTrackedStudy: '',
prevTrackedSeries: [],
trackedStudy: '', trackedStudy: '',
trackedSeries: [], trackedSeries: [],
promptResponse: 0,
}), }),
setPrevTracked: assign(ctx => ({ // Promise resolves w/ `evt.data.*`
prevTrackedStudy: ctx.trackedStudy, setTrackedStudyAndSeries: assign((ctx, evt) => ({
prevTrackedSeries: ctx.trackedSeries.slice(), trackedStudy: evt.data.StudyInstanceUID,
trackedSeries: [evt.data.SeriesInstanceUID],
})), })),
restorePrevTracked: assign(ctx => ({ addTrackedSeries: assign((ctx, evt) => ({
trackedStudy: ctx.prevTrackedStudy, trackedSeries: [...ctx.trackedSeries, evt.data.SeriesInstanceUID],
trackedSeries: ctx.prevTrackedSeries.slice(),
})), })),
clearTrackedSeries: assign(() => ({ removeTrackedSeries: assign((ctx, evt) => ({
trackedStudy: '', trackedSeries: [
trackedSeries: [], ...ctx.trackedSeries(ser => ser !== evt.SeriesInstanceUID),
],
})), })),
trackSeries: assign((ctx, evt) => {
const prevTrackedSeries = ctx.trackedSeries.slice();
return {
trackedStudy: evt.StudyInstanceUID || '',
trackedSeries: [...prevTrackedSeries, evt.SeriesInstanceUID],
};
}),
untrackSeries: assign((ctx, evt) => {
const prevTrackedSeries = ctx.trackedSeries.slice();
return {
trackedSeries: prevTrackedSeries.filter(
serUid => serUid !== evt.SeriesInstanceUID
),
};
}),
}, },
guards: { guards: {
hasNewSeriesForTrackedStudy: (ctx, evt) => promptAccepted: (ctx, evt) => evt.data && evt.data.userResponse === 1,
evt.StudyInstanceUID === ctx.trackedStudy && promptCanceled: (ctx, evt) => evt.data && evt.data.userResponse === 0,
!ctx.trackedSeries.includes(evt.SeriesInstanceUID), promptDeclined: (ctx, evt) => evt.data && evt.data.userResponse === -1,
willTrackNewStudy: ctx => ctx.StudyInstanceUID !== ctx.trackedStudy, hasRemainingTrackedSeries: (ctx, evt) =>
willBeEmpty: (ctx, evt) =>
evt.SeriesInstanceUID &&
ctx.trackedSeries.length === 1 && ctx.trackedSeries.length === 1 &&
ctx.trackedSeries[0] === evt.SeriesInstanceUID, ctx.trackedSeries.includes(evt.SeriesInstanceUID),
acceptResponse: ctx => ctx.promptResponse === 1, isNewStudy: (ctx, evt) => ctx.trackedStudy !== evt.StudyInstanceUID,
cancelResponse: ctx => ctx.promptResponse === 0, isNewSeries: (ctx, evt) =>
rejectResponse: ctx => ctx.promptResponse === -1, !ctx.trackedSeries.includes(evt.SeriesInstanceUID),
}, },
}; };