From 57f1f02a99baf055680d8c0da58be0e6289494f2 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 8 Jan 2026 16:56:02 -0500 Subject: [PATCH 1/6] [BI-2758] - Autocomplete --- src/breeding-insight/dao/ProgramDAO.ts | 9 +++++++++ src/breeding-insight/service/ProgramService.ts | 8 ++++++++ .../ExperimentDetails.vue | 13 +++++++------ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/breeding-insight/dao/ProgramDAO.ts b/src/breeding-insight/dao/ProgramDAO.ts index 96d688b5a..eee7d7edf 100644 --- a/src/breeding-insight/dao/ProgramDAO.ts +++ b/src/breeding-insight/dao/ProgramDAO.ts @@ -108,4 +108,13 @@ export class ProgramDAO { return new BiResponse(data); } + static async getObservationLevelNames(programId: string): Promise { + + const { data } = await api.call({ + url: `${process.env.VUE_APP_BI_API_V1_PATH}/programs/${programId}/brapi/v2/observationlevelnames`, + method: 'get' + }) as Response; + return new BiResponse(data); + + } } diff --git a/src/breeding-insight/service/ProgramService.ts b/src/breeding-insight/service/ProgramService.ts index 7bcacff21..cf7852305 100644 --- a/src/breeding-insight/service/ProgramService.ts +++ b/src/breeding-insight/service/ProgramService.ts @@ -140,5 +140,13 @@ export class ProgramService { else return; } + static async getObservationLevelNames(programId: string): Promise<[ProgramObservationLevel[], Metadata] | void> { + if (programId) { + const { result: { data }, metadata } = await ProgramDAO.getObservationLevelNames(programId); + return [data, metadata]; + } + else return; + } + } diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue index 91774574d..a9cf095d8 100644 --- a/src/views/experiments-and-observations/ExperimentDetails.vue +++ b/src/views/experiments-and-observations/ExperimentDetails.vue @@ -185,6 +185,7 @@ import {DatasetModel} from "@/breeding-insight/model/DatasetModel"; import ExperimentAddCollaboratorModal from "@/components/experiments/ExperimentAddCollaboratorModal.vue"; import ExperimentCollaboratorRemovalModal from "@/components/experiments/ExperimentCollaboratorRemovalModal.vue"; import {ProgramService} from "@/breeding-insight/service/ProgramService"; +import {StringFormatters} from "@/breeding-insight/utils/StringFormatters"; @Component({ components: { @@ -334,23 +335,23 @@ export default class ExperimentDetails extends ProgramsBase { @Watch('$route') async getProgramDatasetNames() { try { - const response = await ProgramService.getObservationLevels(this.activeProgram!.id!); + const response = await ProgramService.getObservationLevelNames(this.activeProgram!.id!); if (response) { - const [observationLevels, metadata] = response; - this.programDatasetNames = observationLevels.map(value => value.name!); + const [observationLevelNames, metadata] = response; + this.programDatasetNames = observationLevelNames.map(value => StringFormatters.toStartCase(value.levelName!)); return; } } catch (error) { - this.$emit('show-error-notification', 'Unable to retrieve program entity names'); + this.$emit('show-error-notification', 'Unable to retrieve program dataset names'); } - this.$emit('show-error-notification', 'Unable to retrieve program entity names'); + this.$emit('show-error-notification', 'Unable to retrieve program dataset names'); return; } //Retrieves entity names in experiment @Watch('datasetMetadata') async getExperimentDatasetNames() { - this.experimentDatasetNames = this.datasetMetadata.map(value => value.name!); + this.experimentDatasetNames = this.datasetMetadata.map(value => StringFormatters.toStartCase(value.name!)); return; } From 5ae3b91557e9155528f0720a16fd47bf765df0d1 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Mon, 12 Jan 2026 20:35:59 -0500 Subject: [PATCH 2/6] [BI-2758] - Fixed UI obs level casing --- src/components/experiments/ExperimentsObservationsTable.vue | 5 +++-- src/views/experiments-and-observations/ExperimentDetails.vue | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/experiments/ExperimentsObservationsTable.vue b/src/components/experiments/ExperimentsObservationsTable.vue index cdf332ab9..641b2d318 100644 --- a/src/components/experiments/ExperimentsObservationsTable.vue +++ b/src/components/experiments/ExperimentsObservationsTable.vue @@ -59,7 +59,7 @@ @@ -97,6 +97,7 @@ import {UPDATE_EXPERIMENT_SORT} from "@/store/sorting/mutation-types"; import {BrAPIUtils} from "@/breeding-insight/utils/BrAPIUtils"; import ExperimentObservationsDownloadModal from "@/components/experiments/ExperimentObservationsDownloadModal.vue"; import {DatasetMetadata} from "@/breeding-insight/model/DatasetMetadata"; +import {StringFormatters} from "../../breeding-insight/utils/StringFormatters"; @Component({ mixins: [validationMixin], @@ -115,7 +116,7 @@ import {DatasetMetadata} from "@/breeding-insight/model/DatasetMetadata"; updateSort: UPDATE_EXPERIMENT_SORT }) }, - data: () => ({Sort, BrAPIUtils}) + data: () => ({Sort, BrAPIUtils, StringFormatters}) }) export default class ExperimentsObservationsTable extends Vue { diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue index a9cf095d8..059360b58 100644 --- a/src/views/experiments-and-observations/ExperimentDetails.vue +++ b/src/views/experiments-and-observations/ExperimentDetails.vue @@ -148,7 +148,7 @@ tag="li" active-class="is-active" > - {{ dataset.name }} + {{ StringFormatters.toStartCase(dataset.name) }} @@ -204,7 +204,8 @@ import {StringFormatters} from "@/breeding-insight/utils/StringFormatters"; }, directives: { ClickOutside - } + }, + data: () => ({StringFormatters}) }) export default class ExperimentDetails extends ProgramsBase { private activeProgram: Program; From 35b73c26944f1c3c8796a03d238c90c9646e4d43 Mon Sep 17 00:00:00 2001 From: nickpalladino Date: Fri, 16 Jan 2026 16:32:53 -0500 Subject: [PATCH 3/6] Capitalize obsUnitIDs --- src/views/import/Dataset.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/views/import/Dataset.vue b/src/views/import/Dataset.vue index b28e7b51e..ec0d49bc9 100644 --- a/src/views/import/Dataset.vue +++ b/src/views/import/Dataset.vue @@ -310,6 +310,7 @@ import {StudyService} from "@/breeding-insight/service/StudyService"; import {BrAPIService, BrAPIType} from '@/breeding-insight/service/BrAPIService'; import {SortOrder} from "@/breeding-insight/model/Sort"; import {DatasetMetadata} from "@/breeding-insight/model/DatasetMetadata"; +import {StringFormatters} from "@/breeding-insight/utils/StringFormatters"; @Component({ components: { @@ -614,8 +615,8 @@ export default class Dataset extends ProgramsBase { } setObsUnitIDLabel(){ - this.obsUnitIDLabel = this.observationUnit + " ObsUnitID" - if (this.isSubEntity) this.subObsUnitIDLabel = this.subObservationUnit + " ObsUnitID" + this.obsUnitIDLabel = StringFormatters.toStartCase(this.observationUnit) + " ObsUnitID" + if (this.isSubEntity) this.subObsUnitIDLabel = StringFormatters.toStartCase(this.subObservationUnit) + " ObsUnitID" } @Watch('$route') From 4872a67e8ebeef4060e23e3615366dc39b1a6534 Mon Sep 17 00:00:00 2001 From: nickpalladino Date: Wed, 21 Jan 2026 14:37:13 -0500 Subject: [PATCH 4/6] Keep all UUIDs to one line, no wrapping --- src/views/import/Dataset.vue | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/views/import/Dataset.vue b/src/views/import/Dataset.vue index ec0d49bc9..6da04d06a 100644 --- a/src/views/import/Dataset.vue +++ b/src/views/import/Dataset.vue @@ -244,11 +244,13 @@ v-slot="props" field="data.obsUnitId" v-bind:label="obsUnitIDLabel" + width="320" sortable searchable - :th-attrs="() => ({scope:'col'})" + :th-attrs="() => ({scope:'col', class: 'uuid-column'})" + cell-class="uuid-column" > - {{ props.row.data.obsUnitId }} + {{ props.row.data.obsUnitId }} - {{ props.row.data.subObsUnitId }} + {{ props.row.data.subObsUnitId }} + + From d71fdb451d8b0cff32458a9560993955457b16cc Mon Sep 17 00:00:00 2001 From: nickpalladino Date: Wed, 21 Jan 2026 14:38:52 -0500 Subject: [PATCH 5/6] Switch to using brapi /observationlevels endpoint for autocomplete data --- .../dao/ObservationUnitDAO.ts | 15 ++++++ .../service/ObservationUnitService.ts | 47 +++++++++++++++++++ .../ExperimentDetails.vue | 17 +++++-- 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 src/breeding-insight/service/ObservationUnitService.ts diff --git a/src/breeding-insight/dao/ObservationUnitDAO.ts b/src/breeding-insight/dao/ObservationUnitDAO.ts index dc0e88f1a..5c05a0754 100644 --- a/src/breeding-insight/dao/ObservationUnitDAO.ts +++ b/src/breeding-insight/dao/ObservationUnitDAO.ts @@ -37,4 +37,19 @@ export class ObservationUnitDAO { return ResultGenerator.err(error); } } + + static async getObservationLevels(programId: string): Promise> { + try { + const { data } = await api.call({ + url: `${process.env.VUE_APP_BI_API_V1_PATH}/programs/${programId}/brapi/v2/observationlevels`, + method: 'get' + }) as Response; + + return ResultGenerator.success(new BiResponse(data)); + + } catch (error) { + return ResultGenerator.err(error); + } + } + } diff --git a/src/breeding-insight/service/ObservationUnitService.ts b/src/breeding-insight/service/ObservationUnitService.ts new file mode 100644 index 000000000..113e1e42c --- /dev/null +++ b/src/breeding-insight/service/ObservationUnitService.ts @@ -0,0 +1,47 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Result, ResultGenerator} from "@/breeding-insight/model/Result"; +import {ObservationUnitDAO} from "@/breeding-insight/dao/ObservationUnitDAO"; +import {BiResponse, Metadata} from "@/breeding-insight/model/BiResponse"; +import {ProgramObservationLevel} from "@/breeding-insight/model/ProgramObservationLevel"; + +export class ObservationUnitService { + + static async getObservationLevels(programId: string): Promise> { + if (!programId) { + return ResultGenerator.err(new Error('Missing or invalid program id')); + } + + let response: Result; + response = await ObservationUnitDAO.getObservationLevels(programId) as Result; + + const frontendModel = (res: BiResponse): [ProgramObservationLevel[], Metadata] => { + let levels: ProgramObservationLevel[] = []; + let {result: {data}, metadata} = res; + + levels = data.map((level: any) => { + return new ProgramObservationLevel(level.levelName!); + }); + + return [levels, metadata]; + } + + return response.applyResult(frontendModel); + } + +} \ No newline at end of file diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue index 059360b58..fda0816e9 100644 --- a/src/views/experiments-and-observations/ExperimentDetails.vue +++ b/src/views/experiments-and-observations/ExperimentDetails.vue @@ -185,7 +185,12 @@ import {DatasetModel} from "@/breeding-insight/model/DatasetModel"; import ExperimentAddCollaboratorModal from "@/components/experiments/ExperimentAddCollaboratorModal.vue"; import ExperimentCollaboratorRemovalModal from "@/components/experiments/ExperimentCollaboratorRemovalModal.vue"; import {ProgramService} from "@/breeding-insight/service/ProgramService"; +import {ObservationUnitService} from "@/breeding-insight/service/ObservationUnitService"; import {StringFormatters} from "@/breeding-insight/utils/StringFormatters"; +import {Observation} from "@/breeding-insight/model/Observation"; +import {Metadata} from "@/breeding-insight/model/BiResponse"; +import {ObservationService} from "@/breeding-insight/service/ObservationService"; +import {ProgramObservationLevel} from "@/breeding-insight/model/ProgramObservationLevel"; @Component({ components: { @@ -336,10 +341,14 @@ export default class ExperimentDetails extends ProgramsBase { @Watch('$route') async getProgramDatasetNames() { try { - const response = await ProgramService.getObservationLevelNames(this.activeProgram!.id!); - if (response) { - const [observationLevelNames, metadata] = response; - this.programDatasetNames = observationLevelNames.map(value => StringFormatters.toStartCase(value.levelName!)); + const response: Result = await ObservationUnitService.getObservationLevels(this.activeProgram!.id!); + if(response.isErr()) { + this.$emit('show-error-notification', 'isErr Unable to retrieve program dataset names'); + } + + if (response.isSuccess()) { + const [observationLevelNames, metadata] = response.value; + this.programDatasetNames = observationLevelNames.map(value => StringFormatters.toStartCase(value.name!)); return; } } catch (error) { From a73e9de43caef7ab1304bd6b80fc5f0d7800b58d Mon Sep 17 00:00:00 2001 From: nickpalladino Date: Tue, 27 Jan 2026 17:02:50 -0500 Subject: [PATCH 6/6] Remove isErr debug text --- src/views/experiments-and-observations/ExperimentDetails.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue index fda0816e9..c5abc9e22 100644 --- a/src/views/experiments-and-observations/ExperimentDetails.vue +++ b/src/views/experiments-and-observations/ExperimentDetails.vue @@ -343,7 +343,7 @@ export default class ExperimentDetails extends ProgramsBase { try { const response: Result = await ObservationUnitService.getObservationLevels(this.activeProgram!.id!); if(response.isErr()) { - this.$emit('show-error-notification', 'isErr Unable to retrieve program dataset names'); + this.$emit('show-error-notification', 'Unable to retrieve program dataset names'); } if (response.isSuccess()) {