Skip to content

Commit 5d02fb1

Browse files
- CHG: Enable ARM build on vuetify branch.
- ADD: Added option to completely hide trait circles in grid. - CHG: Finished trial setup import via BrAPI. -
1 parent fd3cfdf commit 5d02fb1

File tree

11 files changed

+178
-121
lines changed

11 files changed

+178
-121
lines changed

.github/workflows/docker-ci-vuetify.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ jobs:
2323
with:
2424
ref: 'vuetify'
2525

26-
# - name: Set up QEMU
27-
# uses: docker/setup-qemu-action@v1
26+
- name: Set up QEMU
27+
uses: docker/setup-qemu-action@v1
2828

2929
- name: Set up Docker Buildx
3030
uses: docker/setup-buildx-action@v1
@@ -52,7 +52,7 @@ jobs:
5252
with:
5353
build-args: BRANCH=vuetify
5454
context: docker
55-
platforms: linux/amd64
55+
platforms: linux/amd64,linux/arm64
5656
push: ${{ github.event_name != 'pull_request' }}
5757
tags: ${{ steps.meta.outputs.tags }}
5858
labels: ${{ steps.meta.outputs.labels }}

src/components/data/DataCanvas.vue

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,14 @@
144144
isResetting.value = true
145145
146146
nextTick(() => {
147-
if (store.storeHiddenTraits) {
148-
dimensions.value.visibleTraitCount = compProps.trial.traits.filter(t => !store.storeHiddenTraits.includes(t.id || '')).length
147+
if (store.storeHideTraitCircles) {
148+
dimensions.value.visibleTraitCount = 0
149149
} else {
150-
dimensions.value.visibleTraitCount = compProps.trial.traits.length
150+
if (store.storeHiddenTraits) {
151+
dimensions.value.visibleTraitCount = compProps.trial.traits.filter(t => !store.storeHiddenTraits.includes(t.id || '')).length
152+
} else {
153+
dimensions.value.visibleTraitCount = compProps.trial.traits.length
154+
}
151155
}
152156
153157
dimensions.value.rowHeaderWidth = dimensions.value.padding + (dimensions.value.fontSize * `${compProps.trial.layout.rows}`.length)
@@ -275,6 +279,8 @@
275279
reset()
276280
})
277281
282+
watch(() => store.storeHideTraitCircles, async () => reset())
283+
278284
onMounted(() => {
279285
window.addEventListener('resize', reset)
280286
})

src/components/data/DataGrid.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@
281281
282282
const visibleTraits = computed(() => {
283283
if (compProps.trial) {
284-
return compProps.trial.traits.filter(t => !store.storeHiddenTraits.includes(t.id || ''))
284+
return store.storeHideTraitCircles ? [] : compProps.trial.traits.filter(t => !store.storeHiddenTraits.includes(t.id || ''))
285285
} else {
286286
return []
287287
}

src/components/modals/TrialCreationFromBrapiModal.vue

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,30 @@
88

99
<BrapiStudySelect
1010
class="mt-3"
11+
v-model:study="study"
1112
ref="brapiStudySelect"
1213
/>
14+
15+
<v-btn :text="$t('buttonReceiveData')" :prepend-icon="mdiCloudDownload" color="primary" variant="tonal" :disabled="!study" @click="pullData" />
16+
17+
<v-virtual-scroll
18+
max-height="25vh"
19+
class="my-3"
20+
:items="errors"
21+
>
22+
<template #default="{ item }">
23+
<v-list-item :title="item" :prepend-icon="mdiAlertCircle" active active-class="text-error" />
24+
</template>
25+
</v-virtual-scroll>
26+
27+
<LayoutDimensions
28+
class="mt-3"
29+
v-model="layout"
30+
v-model:layout-type="layoutType"
31+
:is-edit="false"
32+
:can-change="false"
33+
v-if="layout"
34+
/>
1335
</v-form>
1436
</template>
1537

@@ -25,12 +47,113 @@
2547
<script setup lang="ts">
2648
import BrapiConfig from '@/components/util/BrapiConfig.vue'
2749
import BrapiStudySelect from '@/components/util/BrapiStudySelect.vue'
50+
import { brapiDefaultCatchHandler, brapiGetObservationUnits } from '@/plugins/brapi'
51+
import type { Study } from '@/plugins/types/brapi'
52+
import type { TrialPlus, BrapiImportCell } from '@/plugins/types/client'
53+
import { CellCategory, DisplayOrder, type Cell, type Layout } from '@/plugins/types/gridscore'
54+
import { getColumnIndex, getRowIndex, isNumber } from '@/plugins/util'
55+
import { mdiAlertCircle, mdiCloudDownload } from '@mdi/js'
2856
57+
import emitter from 'tiny-emitter/instance'
58+
import { useI18n } from 'vue-i18n'
59+
60+
const { t } = useI18n()
61+
62+
const trial = defineModel<TrialPlus>()
2963
const dialog = ref(false)
30-
const canContinue = computed(() => false)
64+
const layout = ref<Layout>()
65+
const study = ref<Study>()
66+
const layoutType = ref<'grid' | 'list'>('grid')
67+
const errors = ref<string[]>([])
68+
const cells = ref<BrapiImportCell[]>([])
69+
70+
const canContinue = computed(() => study.value !== undefined && trial.value !== undefined && cells.value.length > 0)
3171
3272
const brapiStudySelect = useTemplateRef('brapiStudySelect')
3373
74+
function pullData () {
75+
errors.value = []
76+
layout.value = undefined
77+
emitter.emit('show-loading', true)
78+
79+
if (study.value) {
80+
brapiGetObservationUnits(study.value.studyDbId)
81+
.then(result => {
82+
const rows = new Set<number>()
83+
const columns = new Set<number>()
84+
cells.value = []
85+
86+
result.forEach(ou => {
87+
if (ou.observationUnitPosition && ou.observationUnitPosition.positionCoordinateX && ou.observationUnitPosition.positionCoordinateY) {
88+
let columnIndex: number | undefined = undefined
89+
let rowIndex: number | undefined = undefined
90+
let germplasmIdentifier = undefined
91+
let rep = undefined
92+
let brapiId = undefined
93+
let control = undefined
94+
95+
if (ou.observationUnitPosition.positionCoordinateXType === 'GRID_COL' && isNumber(ou.observationUnitPosition.positionCoordinateX, true)) {
96+
columnIndex = +ou.observationUnitPosition.positionCoordinateX
97+
columns.add(columnIndex)
98+
} else {
99+
errors.value.push(t('widgetBrapiTrialImportErrorNoColumnInformation', { germplasm: ou.germplasmName || ou.observationUnitDbId }))
100+
}
101+
if (ou.observationUnitPosition.positionCoordinateYType === 'GRID_ROW' && isNumber(ou.observationUnitPosition.positionCoordinateY, true)) {
102+
rowIndex = +ou.observationUnitPosition.positionCoordinateY
103+
rows.add(rowIndex)
104+
} else {
105+
errors.value.push(t('widgetBrapiTrialImportErrorNoRowInformation', { germplasm: ou.germplasmName || ou.observationUnitDbId }))
106+
}
107+
if (ou.observationUnitName) {
108+
germplasmIdentifier = ou.observationUnitName
109+
} else if (ou.germplasmName) {
110+
germplasmIdentifier = ou.germplasmName
111+
} else {
112+
errors.value.push(t('widgetBrapiTrialImportErrorNoGermplasmName', { germplasm: ou.observationUnitDbId }))
113+
}
114+
if (ou.germplasmDbId) {
115+
brapiId = ou.germplasmDbId
116+
} else {
117+
errors.value.push(t('widgetBrapiTrialImportErrorNoGermplasmDbId', { germplasm: ou.observationUnitDbId }))
118+
}
119+
if (ou.observationUnitPosition.observationLevel && ou.observationUnitPosition.observationLevel.levelName === 'rep') {
120+
rep = ou.observationUnitPosition.observationLevel.levelCode
121+
}
122+
if (ou.observationUnitPosition.entryType && ou.observationUnitPosition.entryType === 'CHECK') {
123+
control = true
124+
}
125+
126+
if (germplasmIdentifier && columnIndex !== undefined && rowIndex !== undefined && brapiId) {
127+
cells.value.push({
128+
germplasm: germplasmIdentifier,
129+
rep,
130+
brapiId,
131+
row: rowIndex,
132+
column: columnIndex,
133+
categories: control ? [CellCategory.CONTROL] : [],
134+
})
135+
}
136+
} else {
137+
errors.value.push(t('widgetBrapiTrialImportErrorNoPlotInformation', { germplasm: ou.germplasmName || ou.observationUnitDbId }))
138+
}
139+
})
140+
141+
if (rows.size > 0 && columns.size > 0 && cells.value.length > 0) {
142+
layout.value = {
143+
rows: rows.size,
144+
columns: columns.size,
145+
rowLabels: [...rows].sort((a, b) => a - b),
146+
columnLabels: [...columns].sort((a, b) => a - b),
147+
columnOrder: DisplayOrder.LEFT_TO_RIGHT,
148+
rowOrder: DisplayOrder.TOP_TO_BOTTOM,
149+
}
150+
}
151+
})
152+
.catch(brapiDefaultCatchHandler)
153+
.finally(() => emitter.emit('show-loading', false))
154+
}
155+
}
156+
34157
function getPrograms () {
35158
brapiStudySelect.value?.updatePrograms()
36159
}
@@ -42,7 +165,31 @@
42165
dialog.value = false
43166
}
44167
function save () {
45-
hide()
168+
const ll = layout.value
169+
if (trial.value && study.value && ll) {
170+
trial.value.name = study.value.studyName
171+
trial.value.description = study.value.studyDescription
172+
trial.value.layout = JSON.parse(JSON.stringify(ll))
173+
174+
const data: { [index: string]: Cell } = {}
175+
176+
cells.value.forEach(c => {
177+
const row = getRowIndex(ll, c.row)
178+
const column = getColumnIndex(ll, c.column)
179+
data[`${row}|${column}`] = {
180+
germplasm: c.germplasm,
181+
categories: c.categories || [],
182+
isMarked: false,
183+
brapiId: c.brapiId,
184+
measurements: {},
185+
comments: [],
186+
}
187+
})
188+
189+
trial.value.data = data
190+
191+
hide()
192+
}
46193
}
47194
48195
defineExpose({

src/components/trial/TraitDropdown.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
/>
3333
</v-list-item>
3434

35+
<v-list-item :title="$t(store.storeCanvasShape === CanvasShape.CIRCLE ? 'buttonHideTraitCircles' : 'buttonHideTraitSquares')" :append-icon="store.storeHideTraitCircles ? mdiCheck : undefined" @click="store.setHideTraitCircles(!store.storeHideTraitCircles)" />
36+
3537
<v-list-item>
3638
<v-btn-group density="compact" class="d-flex">
3739
<v-btn class="flex-grow-1" variant="tonal" :text="$t('buttonSelectAll')" @click="toggleVisibilityAll(true)" :prepend-icon="isSquare ? mdiSquare : mdiCircle" />
@@ -82,7 +84,7 @@
8284
import { useI18n } from 'vue-i18n'
8385
import { useDate } from 'vuetify'
8486
import ResponsiveButton from '@/components/util/ResponsiveButton.vue'
85-
import { mdiCalendarStart, mdiCheckboxBlankOutline, mdiCheckboxMarked, mdiCircle, mdiCircleHalfFull, mdiCircleOutline, mdiMinusBox, mdiSquare, mdiSquareOpacity, mdiSquareOutline, mdiTagMultiple } from '@mdi/js'
87+
import { mdiCalendarStart, mdiCheck, mdiCheckboxBlankOutline, mdiCheckboxMarked, mdiCircle, mdiCircleHalfFull, mdiCircleOutline, mdiMinusBox, mdiSquare, mdiSquareOpacity, mdiSquareOutline, mdiTagMultiple } from '@mdi/js'
8688
8789
const date = useDate()
8890
const store = coreStore()

src/components/trial/TrialCreation.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<v-stepper-window>
4848
<v-stepper-window-item :value="1">
4949
<div class="d-flex justify-end">
50-
<v-btn :text="$t('dropdownOptionBrapiTrialImport')" class="mb-3" prepend-icon="$brapi" @click="trialCreationFromBrapiModal?.show()" />
50+
<v-btn :text="$t('dropdownOptionBrapiTrialImport')" class="mb-3" prepend-icon="$brapi" @click="trialCreationFromBrapiModal?.show()" :disabled="isEdit" />
5151
</div>
5252
<TrialDetails v-model="trial" :is-clone="isClone" :is-edit="isEdit" ref="trialDetails" />
5353
</v-stepper-window-item>
@@ -118,7 +118,7 @@
118118
</template>
119119
</v-card>
120120
</v-bottom-sheet>
121-
<TrialCreationFromBrapiModal ref="trialCreationFromBrapiModal" />
121+
<TrialCreationFromBrapiModal v-model="trial" ref="trialCreationFromBrapiModal" />
122122
</v-container>
123123
</template>
124124

src/components/util/BrapiStudySelect.vue

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -48,32 +48,12 @@
4848
/>
4949
</v-col>
5050
</v-row>
51-
52-
<v-btn :text="$t('buttonReceiveData')" :prepend-icon="mdiCloudDownload" color="primary" variant="tonal" :disabled="!study" @click="pullData" />
53-
54-
<LayoutDimensions
55-
class="mt-3"
56-
v-model="layout"
57-
v-model:layout-type="layoutType"
58-
:is-edit="false"
59-
:can-change="false"
60-
v-if="layout"
61-
/>
6251
</div>
6352
</template>
6453

6554
<script setup lang="ts">
6655
import { brapiDefaultCatchHandler, brapiGetObservationUnits, brapiGetPrograms, brapiGetStudies, brapiGetStudyTypes, brapiGetTrials } from '@/plugins/brapi'
6756
import type { Study, Trial, Program } from '@/plugins/types/brapi'
68-
import type { BrapiImportCell } from '@/plugins/types/client'
69-
import { CellCategory, DisplayOrder, type Layout } from '@/plugins/types/gridscore'
70-
import { isNumber } from '@/plugins/util'
71-
import { mdiCloudDownload } from '@mdi/js'
72-
73-
import emitter from 'tiny-emitter/instance'
74-
import { useI18n } from 'vue-i18n'
75-
76-
const { t } = useI18n()
7757
7858
const programs = ref<Program[]>([])
7959
const program = defineModel<Program>('program')
@@ -84,94 +64,6 @@
8464
const studies = ref<Study[]>([])
8565
const study = defineModel<Study>('study')
8666
87-
const layout = ref<Layout>()
88-
const layoutType = ref<'grid' | 'list'>('grid')
89-
90-
const errors = ref<string[]>([])
91-
92-
function pullData () {
93-
errors.value = []
94-
layout.value = undefined
95-
emitter.emit('show-loading', true)
96-
97-
if (study.value) {
98-
brapiGetObservationUnits(study.value.studyDbId)
99-
.then(result => {
100-
const rows = new Set<number>()
101-
const columns = new Set<number>()
102-
const cells: BrapiImportCell[] = []
103-
104-
result.forEach(ou => {
105-
if (ou.observationUnitPosition && ou.observationUnitPosition.positionCoordinateX && ou.observationUnitPosition.positionCoordinateY) {
106-
let columnIndex: number | undefined = undefined
107-
let rowIndex: number | undefined = undefined
108-
let germplasmIdentifier = undefined
109-
let rep = undefined
110-
let brapiId = undefined
111-
let control = undefined
112-
113-
if (ou.observationUnitPosition.positionCoordinateXType === 'GRID_COL' && isNumber(ou.observationUnitPosition.positionCoordinateX, true)) {
114-
columnIndex = +ou.observationUnitPosition.positionCoordinateX
115-
columns.add(columnIndex)
116-
} else {
117-
errors.value.push(t('widgetBrapiTrialImportErrorNoColumnInformation', { germplasm: ou.germplasmName || ou.observationUnitDbId }))
118-
}
119-
if (ou.observationUnitPosition.positionCoordinateYType === 'GRID_ROW' && isNumber(ou.observationUnitPosition.positionCoordinateY, true)) {
120-
rowIndex = +ou.observationUnitPosition.positionCoordinateY
121-
rows.add(rowIndex)
122-
} else {
123-
errors.value.push(t('widgetBrapiTrialImportErrorNoRowInformation', { germplasm: ou.germplasmName || ou.observationUnitDbId }))
124-
}
125-
if (ou.observationUnitName) {
126-
germplasmIdentifier = ou.observationUnitName
127-
} else if (ou.germplasmName) {
128-
germplasmIdentifier = ou.germplasmName
129-
} else {
130-
errors.value.push(t('widgetBrapiTrialImportErrorNoGermplasmName', { germplasm: ou.observationUnitDbId }))
131-
}
132-
if (ou.germplasmDbId) {
133-
brapiId = ou.germplasmDbId
134-
} else {
135-
errors.value.push(t('widgetBrapiTrialImportErrorNoGermplasmDbId', { germplasm: ou.observationUnitDbId }))
136-
}
137-
if (ou.observationUnitPosition.observationLevel && ou.observationUnitPosition.observationLevel.levelName === 'rep') {
138-
rep = ou.observationUnitPosition.observationLevel.levelCode
139-
}
140-
if (ou.observationUnitPosition.entryType && ou.observationUnitPosition.entryType === 'CHECK') {
141-
control = true
142-
}
143-
144-
if (germplasmIdentifier && columnIndex !== undefined && rowIndex !== undefined && brapiId) {
145-
cells.push({
146-
germplasm: germplasmIdentifier,
147-
rep,
148-
brapiId,
149-
row: rowIndex,
150-
column: columnIndex,
151-
categories: control ? [CellCategory.CONTROL] : [],
152-
})
153-
}
154-
} else {
155-
errors.value.push(t('widgetBrapiTrialImportErrorNoPlotInformation', { germplasm: ou.germplasmName || ou.observationUnitDbId }))
156-
}
157-
})
158-
159-
if (rows.size > 0 && columns.size > 0 && cells.length > 0) {
160-
layout.value = {
161-
rows: rows.size,
162-
columns: columns.size,
163-
rowLabels: [...rows].sort((a, b) => a - b),
164-
columnLabels: [...columns].sort((a, b) => a - b),
165-
columnOrder: DisplayOrder.LEFT_TO_RIGHT,
166-
rowOrder: DisplayOrder.TOP_TO_BOTTOM,
167-
}
168-
}
169-
})
170-
.catch(brapiDefaultCatchHandler)
171-
.finally(() => emitter.emit('show-loading', false))
172-
}
173-
}
174-
17567
function updatePrograms () {
17668
brapiGetPrograms()
17769
.then(pr => {

0 commit comments

Comments
 (0)