diff --git a/app/src/robot/api-client/client.js b/app/src/robot/api-client/client.js index 4c8558bc14a..989d3bba649 100755 --- a/app/src/robot/api-client/client.js +++ b/app/src/robot/api-client/client.js @@ -584,12 +584,19 @@ export function client(dispatch) { }) .map(t => t._id) + // ensure IDs are actually present in containers list + // RPC API as of 3.16 may return bogus tipracks in pipette tipracks list + const tipRacks = union( + tipRacksFromInstrument, + tipRacksFromContainers + ).filter(id => containers.some(c => c._id === id)) + update.pipettesByMount[mount] = { _id, mount, name, channels, - tipRacks: union(tipRacksFromInstrument, tipRacksFromContainers), + tipRacks, requestedAs: requested_as, } } diff --git a/app/src/robot/selectors.js b/app/src/robot/selectors.js index 36bcf6dcb94..404c30a211c 100644 --- a/app/src/robot/selectors.js +++ b/app/src/robot/selectors.js @@ -481,8 +481,20 @@ export const getTipracksByMount: ( state: State ) => TiprackByMountMap = createSelector( getTipracks, - tipracks => ({ - left: tipracks.find(tr => tr.calibratorMount === 'left') || null, - right: tipracks.find(tr => tr.calibratorMount === 'right') || null, - }) + getPipettesByMount, + (tipracks, pipettesMap) => { + return PIPETTE_MOUNTS.reduce( + (tiprackMap, mount) => { + const byCalibrator = tipracks.find(tr => tr.calibratorMount === mount) + const byTiprackList = tipracks.find(tr => + (pipettesMap[mount]?.tipRacks ?? []).includes(tr._id) + ) + + tiprackMap[mount] = byCalibrator ?? byTiprackList ?? null + + return tiprackMap + }, + { left: null, right: null } + ) + } ) diff --git a/app/src/robot/test/api-client.test.js b/app/src/robot/test/api-client.test.js index 6184ae8954c..a058dc2e526 100755 --- a/app/src/robot/test/api-client.test.js +++ b/app/src/robot/test/api-client.test.js @@ -468,6 +468,8 @@ describe('api client', () => { }, ] + session.containers = [{ _id: 3 }, { _id: 4 }, { _id: 5 }] + return sendConnect().then(() => expect(dispatch).toHaveBeenCalledWith(expected) ) @@ -555,7 +557,9 @@ describe('api client', () => { mount: 'right', name: 'p50', channels: 8, - tip_racks: [], + // guard against bogus tipracks in this array, which RPC API has been + // observed doing as of 3.16 + tip_racks: [{ _id: 888 }], requested_as: 'foo', }, { @@ -563,7 +567,7 @@ describe('api client', () => { mount: 'left', name: 'p200', channels: 1, - tip_racks: [], + tip_racks: [{ _id: 999 }], requested_as: 'bar', }, ] @@ -581,9 +585,9 @@ describe('api client', () => { }, ] - return sendConnect().then(() => + return sendConnect().then(() => { expect(dispatch).toHaveBeenCalledWith(expected) - ) + }) }) it('maps api modules to modules by slot', () => { diff --git a/app/src/robot/test/selectors.test.js b/app/src/robot/test/selectors.test.js index 750e43d6062..44383bd9cf4 100644 --- a/app/src/robot/test/selectors.test.js +++ b/app/src/robot/test/selectors.test.js @@ -742,7 +742,7 @@ describe('robot selectors', () => { }) }) - it('getTipracksByMount', () => { + it('returns tipracks by calibratorMount with getTipracksByMount', () => { expect(getTipracksByMount(state)).toEqual({ left: { slot: '2', @@ -766,6 +766,65 @@ describe('robot selectors', () => { }, }) }) + + it('uses tiprack lists from pipettes in getTipracksByMount if no calibratorMount', () => { + state = makeState({ + session: { + labwareBySlot: { + 1: { + _id: 1, + slot: '1', + type: 's', + isTiprack: true, + calibratorMount: 'right', + }, + 2: { + _id: 2, + slot: '2', + type: 'm', + isTiprack: true, + calibratorMount: 'right', + }, + }, + pipettesByMount: { + left: { name: 'p200', mount: 'left', tipRacks: [2] }, + right: { name: 'p50', mount: 'right', tipRacks: [1, 2] }, + }, + }, + calibration: { + labwareBySlot: {}, + confirmedBySlot: {}, + calibrationRequest: { type: '', inProgress: false, error: null }, + probedByMount: {}, + tipOnByMount: {}, + }, + }) + + expect(getTipracksByMount(state)).toEqual({ + left: { + _id: 2, + slot: '2', + type: 'm', + isTiprack: true, + isMoving: false, + calibration: 'unconfirmed', + confirmed: false, + calibratorMount: 'right', + definition: null, + }, + right: { + _id: 1, + slot: '1', + type: 's', + isTiprack: true, + isMoving: false, + calibration: 'unconfirmed', + confirmed: false, + calibratorMount: 'right', + definition: null, + }, + }) + }) }) it('getDeckPopulated', () => {