Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

develop into master #1599

Merged
merged 39 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
138df61
fix: adjust spacing between card sections
StephenHulme Jan 23, 2024
9317909
fix: add header to sample arraying page
StephenHulme Jan 23, 2024
ecf096a
fix: restore missing well ID
StephenHulme Jan 26, 2024
d3a1e74
feat: add tube colour to summary
StephenHulme Feb 12, 2024
eabd1cb
feat: add tube colour to scanning
StephenHulme Feb 13, 2024
2bd15f4
feat: add tube colour to plate
StephenHulme Feb 13, 2024
9ea2290
refactor: rename well colour -> tube colour
StephenHulme Feb 13, 2024
f6412dc
style: lint
StephenHulme Feb 13, 2024
d0043ba
tests: update to reflect colour by barcode
StephenHulme Feb 13, 2024
9179b19
style: add comment
StephenHulme Feb 13, 2024
e75f7e2
refactor: move findUniqueIndex to wellHelpers
StephenHulme Feb 13, 2024
5d77c56
tests: add wellHelpers tests
StephenHulme Feb 13, 2024
b2e883d
Update core-js to version 3.36.0
depfu[bot] Feb 15, 2024
e8139ba
Merge branch 'develop' into dpl-954-colour-code-wells-on-arraying-page
StephenHulme Feb 16, 2024
697040d
refactor: rename pool_index -> colour_index
StephenHulme Feb 20, 2024
6591d9c
fix: add tooltips to wells
StephenHulme Feb 20, 2024
9023d86
feat: show human barcode on tooltip label
StephenHulme Feb 20, 2024
c3cd4e6
test: update tests to reflect pool_index changes
StephenHulme Feb 20, 2024
fa4078a
test: update tests to reflect sample arraying page header changes
StephenHulme Feb 20, 2024
055aafd
test: update tests to reflect tooltip changes
StephenHulme Feb 20, 2024
e174b10
test: address some test warnings
StephenHulme Feb 20, 2024
4799042
test: add test to reflect sample arraying page header changes
StephenHulme Feb 20, 2024
176560a
fix: clean-up tube validity conditions
StephenHulme Feb 20, 2024
9735757
test: add tests to show the effect of changing tubes and validity
StephenHulme Feb 20, 2024
593210e
tests: add tests for colours in TubeArraySummary
StephenHulme Feb 20, 2024
391f769
fix: include labware state in tube array summary behaviour
StephenHulme Feb 21, 2024
d5cbfa5
Merge branch 'develop' into dpl-954-colour-code-wells-on-arraying-page
StephenHulme Feb 21, 2024
5338e75
refactor: rename value -> summary
StephenHulme Feb 22, 2024
7faf96f
refactor: use different variable in targetWells to streamline access
StephenHulme Feb 23, 2024
b4746cc
style: add some docs to functions
StephenHulme Feb 23, 2024
89b49b8
refactor: increase code-style consistency
StephenHulme Feb 23, 2024
4ded3e7
docs: add more function doc-strings
StephenHulme Feb 23, 2024
826d23c
docs: add more doc-strings
StephenHulme Feb 23, 2024
77f7eb1
Merge pull request #1584 from sanger/depfu/update/yarn/core-js-3.36.0
yoldas Feb 23, 2024
16b58cd
Merge pull request #1580 from sanger/dpl-954-colour-code-wells-on-arr…
StephenHulme Feb 27, 2024
e159e68
separated export file download for tnanoseq to fetch diluent_volume f…
andrewsparkes Feb 27, 2024
2eb170c
fix test includes
andrewsparkes Feb 27, 2024
526b4b3
Merge pull request #1597 from sanger/tnanoseq_fix_27th_feb
andrewsparkes Feb 28, 2024
2bedafd
updated version number
andrewsparkes Feb 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.47.0
3.47.1
114 changes: 104 additions & 10 deletions app/javascript/multi-stamp-tubes/components/MultiStampTubes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ describe('MultiStampTubes', () => {
// triggering change events on unmounted components
return shallowMount(MultiStampTubes, {
propsData: {
parentPurposeName: 'parent',
purposeName: 'purpose',
purposeUuid: 'test',
targetRows: '8',
targetColumns: '12',
sourceTubes: '4',
purposeUuid: 'test',
requestsFilter: 'null',
targetUrl: 'example/example',
locationObj: mockLocation,
Expand All @@ -33,6 +35,12 @@ describe('MultiStampTubes', () => {
})
}

it('renders the header', () => {
const wrapper = wrapperFactory()

expect(wrapper.findComponent('b-card-stub').attributes('header')).toEqual('Sample Arraying: parent → purpose')
})

it('disables creation if there are no tubes', () => {
const wrapper = wrapperFactory()

Expand Down Expand Up @@ -242,22 +250,22 @@ describe('MultiStampTubes', () => {
])
})

it('passes on the layout', () => {
it('passes on the layout, assigning colour by machine barcode', () => {
const tube1 = {
state: 'valid',
labware: tubeFactory({ uuid: 'tube-uuid-1' }),
labware: tubeFactory({ uuid: 'tube-uuid-1', labware_barcode: { machine_barcode: 'barcode-1' } }),
}
const tube2 = {
state: 'valid',
labware: tubeFactory({ uuid: 'tube-uuid-2' }),
labware: tubeFactory({ uuid: 'tube-uuid-2', labware_barcode: { machine_barcode: 'barcode-2' } }),
}
const tube3 = {
state: 'valid',
labware: tubeFactory({ uuid: 'tube-uuid-3' }),
labware: tubeFactory({ uuid: 'tube-uuid-3', labware_barcode: { machine_barcode: 'barcode-2' } }),
}
const tube4 = {
state: 'valid',
labware: tubeFactory({ uuid: 'tube-uuid-4' }),
labware: tubeFactory({ uuid: 'tube-uuid-4', labware_barcode: { machine_barcode: 'barcode-4' } }),
}
const wrapper = wrapperFactory()
wrapper.vm.updateTube(1, tube1)
Expand All @@ -266,11 +274,97 @@ describe('MultiStampTubes', () => {
wrapper.vm.updateTube(4, tube4)

expect(wrapper.vm.targetWells).toEqual({
A1: { pool_index: 1 },
B1: { pool_index: 2 },
C1: { pool_index: 3 },
D1: { pool_index: 4 },
A1: { colour_index: 1 },
B1: { colour_index: 2 },
C1: { colour_index: 2 },
D1: { colour_index: 3 },
})
})

it('recalculates the colour index when tubes are updated', () => {
const noTube = { state: 'empty', labware: null }
const tube1 = {
state: 'valid',
labware: tubeFactory({ uuid: 'tube-uuid-1', labware_barcode: { machine_barcode: 'barcode-1' } }),
}
const tube2 = {
state: 'valid',
labware: tubeFactory({ uuid: 'tube-uuid-2', labware_barcode: { machine_barcode: 'barcode-2' } }),
}
const wrapper = wrapperFactory()

// add two different tubes
wrapper.vm.updateTube(1, tube1)
wrapper.vm.updateTube(2, tube2)
expect(wrapper.vm.targetWells).toEqual({
A1: { colour_index: 1 },
B1: { colour_index: 2 },
})

// remove the first tube
wrapper.vm.updateTube(1, noTube)
expect(wrapper.vm.targetWells).toEqual({
B1: { colour_index: 1 },
})

// add the second tube again, but in the first position
wrapper.vm.updateTube(1, tube2)
expect(wrapper.vm.targetWells).toEqual({
A1: { colour_index: 1 },
B1: { colour_index: 1 },
})
})

it('renders the tube colours based on tube state', () => {
const wrapper = wrapperFactory()

const emptyTube = {
state: 'empty',
labware: null,
}
const notFoundTube = {
state: 'invalid',
labware: undefined,
}
const unknownTube = {
state: 'valid',
labware: tubeFactory({ uuid: 't-unknown', labware_barcode: { machine_barcode: 'UNKNOWN' }, state: 'unknown' }),
}
const pendingTube = {
state: 'valid',
labware: tubeFactory({ uuid: 't-pending', labware_barcode: { machine_barcode: 'PENDING' }, state: 'pending' }),
}
const passedTube = {
state: 'valid',
labware: tubeFactory({ uuid: 't-passed', labware_barcode: { machine_barcode: 'PASSED' }, state: 'passed' }),
}

wrapper.vm.updateTube(1, emptyTube)
wrapper.vm.updateTube(2, notFoundTube)
wrapper.vm.updateTube(3, unknownTube)
wrapper.vm.updateTube(4, pendingTube)
wrapper.vm.updateTube(5, passedTube)

// shows only the (valid) tubes that are passed to the plate
expect(wrapper.vm.targetWells).toEqual({
C1: { colour_index: 1 },
D1: { colour_index: 2 },
E1: { colour_index: 3 },
})

// shows only the (valid) tubes that are passed to labware-scan
expect(wrapper.vm.tubes.length).toEqual(5)
let colourIndices = []
for (let i = 0; i < 5; i++) {
let result = wrapper.vm.colourIndex(i)
colourIndices.push(result)
}

expect(colourIndices).toEqual([-1, -1, 1, 2, 3])

// shows all the tubes (valid and invalid) that are passed to tube-array-summary
// no colour index is assigned to tubes at this stage and all the tubes are passed
// as-is to the tube-array-summary component where the colour index is assigned
})

it('does not display an alert if no invalid transfers are present', () => {
Expand Down
103 changes: 88 additions & 15 deletions app/javascript/multi-stamp-tubes/components/MultiStampTubes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
<lb-page>
<lb-loading-modal v-if="loading" :message="progressMessage" />
<lb-main-content>
<b-card bg-variant="dark" text-variant="white">
<b-card bg-variant="dark" text-variant="white" :header="header" header-tag="h3">
<lb-plate
caption="Layout of the new plate"
:rows="targetRowsNumber"
:columns="targetColumnsNumber"
:wells="targetWells"
/>
</b-card>
<b-card bg-variant="dark" text-variant="white">
<hr />
<lb-tube-array-summary :tubes="tubes" />
</b-card>
</lb-main-content>
Expand All @@ -28,7 +27,7 @@
:includes="tubeIncludes"
:fields="tubeFields"
:validators="scanValidation"
:colour-index="i"
:colour-index="colourIndex(i - 1)"
:labware-type="'tube'"
:valid-message="''"
@change="updateTube(i, $event)"
Expand Down Expand Up @@ -60,7 +59,7 @@ import resources from 'shared/resources'
import { transferTubesCreator } from 'shared/transfersCreators'
import { transfersForTubes } from 'shared/transfersLayouts'
import { buildTubeObjs } from 'shared/tubeHelpers'
import { indexToName } from 'shared/wellHelpers'
import { findUniqueIndex, indexToName } from 'shared/wellHelpers'
import MultiStampTubesTransfers from './MultiStampTubesTransfers'
import TubeArraySummary from './TubeArraySummary'
import filterProps from './filterProps'
Expand Down Expand Up @@ -99,6 +98,12 @@ export default {
// Limber plate purpose UUID
purposeUuid: { type: String, required: true },

// Limber plate purpose name
purposeName: { type: String, required: true },

// Limber parent purpose name
parentPurposeName: { type: String, required: true },

// Limber target Asset URL for posting the transfers
targetUrl: { type: String, required: true },

Expand Down Expand Up @@ -161,6 +166,10 @@ export default {
}
},
computed: {
// Returns the header for the page
header() {
return `Sample Arraying: ${this.parentPurposeName} → ${this.purposeName}`
},
sourceTubeNumber() {
return Number.parseInt(this.sourceTubes)
},
Expand All @@ -170,22 +179,33 @@ export default {
targetColumnsNumber() {
return Number.parseInt(this.targetColumns)
},
// Returns a boolean indicating whether the provided tubes are valid.
// Used to enable and disable the 'Create' button.
valid() {
return (
this.unsuitableTubes.length === 0 && // None of the tubes are invalid
this.validTransfers.length > 0 && // We have at least one transfer
this.transfersCreatorObj.isValid
)
},
// Returns an array of tubes that are in a 'valid' state.
validTubes() {
return this.tubes.filter((tube) => tube.state === 'valid')
},
// Returns an array of tubes that are not in a 'valid' or 'empty' state.
unsuitableTubes() {
return this.tubes.filter((tube) => !(tube.state === 'valid' || tube.state === 'empty'))
},
transfers() {
return transfersForTubes(this.validTubes)
},
// validTransfers returns an array with the following structure:
//
// [
// { tubeObj: { index: 0, tube: {...} }, targetWell: 'A1' },
// { tubeObj: { index: 1, tube: {...} }, targetWell: 'A2' },
// ...etc...
// ]
validTransfers() {
return this.transfers.valid
},
Expand All @@ -197,20 +217,26 @@ export default {
transfersCreatorComponent() {
return transfersCreatorsComponentsMap[this.transfersCreator]
},
// map of well position to pool index (just a number that controls the colour)
// map of well positions tube metadata, eg:
// {
// "A1": 2,
// "B4": 9,
// "A1": {
// colour_index: 1,
// human_barcode: "DN123456"
// },
// "B4": {
// colour_index: 2,
// human_barcode: "DN123457"
// },
// ...
// }
targetWells() {
const wells = {}
for (let i = 0; i < this.validTransfers.length; i++) {
wells[this.validTransfers[i].targetWell] = {
pool_index: this.validTransfers[i].tubeObj.index + 1,
return this.validTransfers.reduce((acc, transfer) => {
acc[transfer.targetWell] = {
colour_index: this.colourIndex(transfer.tubeObj.index),
human_barcode: transfer.tubeObj.tube.labware_barcode.human_barcode,
}
}
return wells
return acc
}, {})
},
tubeIncludes() {
return filterProps.tubeIncludes
Expand All @@ -233,14 +259,61 @@ export default {
},
},
methods: {
// Given a 0-based well index, return the well name.
// e.g. 0 -> A1, 1 -> A2, etc.
wellIndexToName(index) {
return indexToName(index, this.targetRowsNumber)
},
// Determines the colour of the tube based on its barcode,
// where tubes with the same barcode have the same colour.
// Returns an integer that is used elsewhere to build the colour class name (see colours.css).
// Returns -1 if the tube is not valid.
colourIndex(tubeIndex) {
let colour_index = -1

const tube = this.tubes[tubeIndex]
if (tube.state !== 'valid') return colour_index

const tube_machine_barcode = tube.labware.labware_barcode.machine_barcode
const tube_machine_barcodes = this.tubes
.filter((tube) => tube.state === 'valid')
.map((tube) => tube.labware.labware_barcode.machine_barcode)

const barcode_index = findUniqueIndex(tube_machine_barcodes, tube_machine_barcode)
if (barcode_index !== -1) colour_index = barcode_index + 1

return colour_index
},
/**
* The entry point for updating tubes attached to the plate.
* Called when a tube is scanned into a well.
*
* @param {Number} index - The (1-based) index of the tube in the tubes array.
* @param {Object} data - The tube object returned from the scan, which includes:
* - labware: Contains details about the labware, such as id, uuid, and barcode details.
* - state: The "scanned" state of the tube, e.g., "valid".
* @example {
* labware: {
* id: "47",
* uuid: "1234-5678-91011",
* labware_barcode: {
* ean13_barcode: "3980000035714",
* human_barcode: "NT35G",
* machine_barcode: "3980000035714"
* },
* links: {...},
* receptacle: {...},
* type: "tubes",
* state: "passed"
* },
* state: "valid"
* }
*/
updateTube(index, data) {
this.$set(this.tubes, index - 1, { ...data, index: index - 1 })
},
apiTransfers() {
// what we want to transfer when cteating the plate
// what we want to transfer when creating the plate
return transferTubesCreator(this.validTransfers, this.transfersCreatorObj.extraParams)
},
createPlate() {
Expand Down
Loading
Loading