import { ofType } from 'redux-observable' ; import { of } from 'rxjs' ; import { map , switchMap } from 'rxjs/operators' ; import { GET , POST , fetchRobotApi } from '../../robot-api' ; import { withRobotHost } from '../../robot-api/operators' ; import { getAttachedPipettes } from '../../pipettes' ; import * as Actions from '../actions' ; import * as Constants from '../constants' ; import type { Observable } from 'rxjs' ; import type { State , Action , Epic } from '../../types' ; import type { RobotApiRequestOptions , RobotApiResponse , RobotHost , } from '../../robot-api/types' ; import type { MoveAction , PositionsResponse } from '../types' ; const mapActionToRequest = ( action , state , positionsResponse ) : RobotApiRequestOptions => { const { robotName , position , mount } = action . payload ; const attachedPipettes = getAttachedPipettes ( state , robotName ) ; const apiPosition = position === Constants . CHANGE_PIPETTE ? positionsResponse . positions . change_pipette : positionsResponse . positions . attach_tip ; const body = apiPosition . target === Constants . MOUNT ? { mount , target : Constants . MOUNT , point : apiPosition [ mount ] } : { mount , target : Constants . PIPETTE , point : apiPosition . point , model : attachedPipettes [ mount ] ?. model || null , } ; return { method : POST , path : Constants . MOVE_PATH , body } ; } ; const mapResponseToAction = ( response , originalAction ) : Action => { const { host , body , ... responseMeta } = response ; const meta = { ... originalAction . meta , response : responseMeta } ; return response . ok ? Actions . moveSuccess ( host . name , meta ) : Actions . moveFailure ( host . name , body , meta ) ; } ; const fetchPositionsRequest = { method : GET , path : Constants . POSITIONS_PATH } ; const disengageMotorsRequest = { method : POST , path : Constants . DISENGAGE_MOTORS_PATH , body : { axes : [ 'a' , 'b' , 'c' , 'z' ] } , } ; export const moveEpic = ( action$ , state$ ) => { return action$ . pipe ( ofType < Action , MoveAction > ( Constants . MOVE ) , withRobotHost ( state$ , a => a . payload . robotName ) , switchMap < [ MoveAction , State , RobotHost ] , Observable < Action > > ( ( [ action , state , host ] ) => { return fetchRobotApi ( host , fetchPositionsRequest ) . pipe ( switchMap ( positionsResponse => { return positionsResponse . ok ? fetchRobotApi ( host , mapActionToRequest ( action , state , positionsResponse . body ) ) : of ( positionsResponse ) ; } ) , switchMap ( maybeMoveSuccess => { return maybeMoveSuccess . ok && action . payload . disengageMotors ? fetchRobotApi ( host , disengageMotorsRequest ) . pipe ( map ( disengageResponse => disengageResponse . ok ? maybeMoveSuccess : disengageResponse ) ) : of ( maybeMoveSuccess ) ; } ) , map ( response => mapResponseToAction ( response , action ) ) ) ; } ) ) ; } ;