- Prepare a dataset for repeated observations within {{ experimentObservationUnit }}.
+ Prepare a dataset for repeated observations within {{ defaultObservationLevel }}.
@@ -36,14 +36,14 @@
-
+
@@ -83,6 +83,8 @@ import {validationMixin} from "vuelidate";
import FormModal from "@/components/modals/FormModal.vue";
import AutoCompleteField from "@/components/forms/AutoCompleteField.vue";
import BasicInputField from "@/components/forms/BasicInputField.vue";
+import {Trial} from "@/breeding-insight/model/Trial";
+import {between, maxLength, minLength, required, integer} from 'vuelidate/lib/validators'
@Component({
mixins: [validationMixin],
@@ -97,28 +99,44 @@ export default class SubEntityDatasetModal extends Vue {
@Prop()
modalClass?: string;
@Prop()
- create!: () => boolean;
+ create!: (string, number) => boolean;
@Prop()
active!: boolean;
@Prop()
datasetNameOptions?: string[];
@Prop()
- experimentObservationUnit!: string;
+ experiment!: Trial;
+ @Prop()
+ defaultObservationLevel?: string;
+
+ // Reactive, private (would not be reactive if declared without initial values).
+ private datasetName: string = null;
+ private datasetRepeatedMeasures: number = null;
- private datasetName?: string;
- private datasetRepeatedMeasures?: number;
+ // Form validations. TODO: wire up validations!
+ formValidations = {
+ name: {required, minLength: minLength(1)},
+ repeatedMeasures: {
+ required,
+ between: between(1, 100), // Note: number of repeated measures is capped at 100 for performance considerations.
+ integer
+ }
+ }
- closeSubEntityDatasetModal(){
- // Emit deactivate event, allows parent to reset form state, for example.
+ deactivateModal(){
+ // Reset form state.
+ this.datasetName = null;
+ this.datasetRepeatedMeasures = null;
+ // Emit deactivate event.
this.$emit('deactivate');
}
invokeCreate(){
// Invoke the create prop, which returns true if create succeeded.
- if (this.create())
+ if (this.create(this.datasetName, this.datasetRepeatedMeasures))
{
// Close and deactivate modal.
- this.closeSubEntityDatasetModal();
+ this.deactivateModal();
}
}
diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue
index 9765c57e1..2557f8632 100644
--- a/src/views/experiments-and-observations/ExperimentDetails.vue
+++ b/src/views/experiments-and-observations/ExperimentDetails.vue
@@ -29,17 +29,19 @@
v-bind:modal-title="`Download ${experiment.trialName}`"
v-bind:trial-id="experimentUUID"
v-bind:active="downloadModalActive"
- v-on:show-error-notification ="$emit('show-error-notification', $event)"
+ v-on:show-error-notification="$emit('show-error-notification', $event)"
v-on:deactivate="downloadModalActive = false"
/>
@@ -74,7 +76,7 @@
v-bind:action-menu-items="actions"
v-on:import-file="importFile()"
v-on:download-file="downloadFile()"
- v-on:create-sub-entity-dataset="createSubEntityDataset()"
+ v-on:create-sub-entity-dataset="openSubEntityModal()"
/>
@@ -84,11 +86,14 @@
@@ -163,7 +168,13 @@ export default class ExperimentDetails extends ProgramsBase {
this.downloadModalActive = true;
}
- private createSubEntityDataset() {
+ private createSubEntityDataset(datasetName: string, repeatedMeasures: number): boolean {
+ // TODO: implement!
+ console.log("createSubEntityDataset invoked with arguments: datasetName=" + datasetName + ", repeatedMeasures=" + repeatedMeasures);
+ return true;
+ }
+
+ private openSubEntityModal() {
this.subEntityModalActive = true;
}
@@ -198,10 +209,23 @@ export default class ExperimentDetails extends ProgramsBase {
// return this.experiment.additionalInfo.environmentsCount;
// }
+ // The options to make available in the autocomplete.
+ get datasetNameOptions(): string[] {
+ // TODO: implement!
+ return ['Plot', 'Plant', 'Leaf']
+ }
+
+ // The datasets that exist for this experiment already.
+ get datasetNames(): string[] {
+ // TODO: implement!
+ return ['Plot'];
+ }
- get experimentObservationUnit(): string {
- // TODO: get the actual default observation unit/level for this experiment!
- return 'plot';
+ get experimentObservationUnit(): string | null {
+ if (this.experiment && this.experiment.additionalInfo && this.experiment.additionalInfo.defaultObservationLevel) {
+ return this.experiment.additionalInfo.defaultObservationLevel;
+ }
+ return null;
}
@Watch('$route')
From d3ed23e1e9d873b353d1ad430257e5ef4f23e670 Mon Sep 17 00:00:00 2001
From: mlm483 <128052931+mlm483@users.noreply.github.com>
Date: Thu, 30 May 2024 16:37:06 -0400
Subject: [PATCH 3/9] [BI-2109] - used experiments datasets array
---
src/breeding-insight/dao/ExperimentDAO.ts | 16 ++++++++++++++
.../service/ExperimentService.ts | 6 +++++
.../ExperimentsObservationsTable.vue | 2 +-
.../ExperimentDetails.vue | 22 +++++++++++--------
4 files changed, 36 insertions(+), 10 deletions(-)
diff --git a/src/breeding-insight/dao/ExperimentDAO.ts b/src/breeding-insight/dao/ExperimentDAO.ts
index 83468197e..381e7b5ea 100644
--- a/src/breeding-insight/dao/ExperimentDAO.ts
+++ b/src/breeding-insight/dao/ExperimentDAO.ts
@@ -38,6 +38,7 @@ export class ExperimentDAO {
return ResultGenerator.err(error);
}
}
+
static async getDatasetById(programId: string, experimentId: string, datasetId: string, stats: boolean): Promise> {
const config: any = {};
config.url = `${process.env.VUE_APP_BI_API_V1_PATH}/programs/${programId}/experiments/${experimentId}/dataset/${datasetId}`;
@@ -57,4 +58,19 @@ export class ExperimentDAO {
}
}
+ static async createSubEntityDataset(programId: string, experimentId: string, name: string, repeatedMeasures: number): Promise> {
+ const config: any = {};
+ config.url = `${process.env.VUE_APP_BI_API_V1_PATH}/programs/${programId}/experiments/${experimentId}/dataset`;
+ config.method = 'post';
+ config.programId = programId;
+ config.experimentId = experimentId;
+ config.data = {name: name, repeatedMeasures: repeatedMeasures} // Corresponds to SubEntityDatasetRequest in bi-api.
+ try {
+ const res = await api.call(config) as Response;
+ let { result } = res.data;
+ return ResultGenerator.success(result);
+ } catch (error) {
+ return ResultGenerator.err(error);
+ }
+ }
}
diff --git a/src/breeding-insight/service/ExperimentService.ts b/src/breeding-insight/service/ExperimentService.ts
index 8de5d4f59..ab8ca5ddf 100644
--- a/src/breeding-insight/service/ExperimentService.ts
+++ b/src/breeding-insight/service/ExperimentService.ts
@@ -36,4 +36,10 @@ export class ExperimentService {
return await ExperimentDAO.getDatasetById(programId,experimentId, datasetId, true);
}
+ static async createSubEntityDataset(programId: string, experimentId: string, name: string, repeatedMeasures: number): Promise> {
+ if (!programId) {
+ return ResultGenerator.err(new Error('Missing or invalid program id'));
+ }
+ return await ExperimentDAO.createSubEntityDataset(programId, experimentId, name, repeatedMeasures);
+ }
}
diff --git a/src/components/experiments/ExperimentsObservationsTable.vue b/src/components/experiments/ExperimentsObservationsTable.vue
index 32a7157f5..5f55f5a85 100644
--- a/src/components/experiments/ExperimentsObservationsTable.vue
+++ b/src/components/experiments/ExperimentsObservationsTable.vue
@@ -58,7 +58,7 @@
- {{ dataset }}
+ {{ dataset.name }}
diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue
index 2557f8632..24939c375 100644
--- a/src/views/experiments-and-observations/ExperimentDetails.vue
+++ b/src/views/experiments-and-observations/ExperimentDetails.vue
@@ -86,13 +86,13 @@
@@ -169,8 +169,9 @@ export default class ExperimentDetails extends ProgramsBase {
}
private createSubEntityDataset(datasetName: string, repeatedMeasures: number): boolean {
- // TODO: implement!
+ // TODO: implement exception handling!
console.log("createSubEntityDataset invoked with arguments: datasetName=" + datasetName + ", repeatedMeasures=" + repeatedMeasures);
+ ExperimentService.createSubEntityDataset(this.activeProgram!.id!, this.experimentUUID, datasetName, repeatedMeasures);
return true;
}
@@ -216,13 +217,16 @@ export default class ExperimentDetails extends ProgramsBase {
}
// The datasets that exist for this experiment already.
- get datasetNames(): string[] {
- // TODO: implement!
- return ['Plot'];
+ get datasets(): string[] | null {
+ console.log(this.experiment.additionalInfo.datasets);
+ if (this.experiment && this.experiment.additionalInfo) {
+ return this.experiment.additionalInfo.datasets;
+ }
+ return null;
}
get experimentObservationUnit(): string | null {
- if (this.experiment && this.experiment.additionalInfo && this.experiment.additionalInfo.defaultObservationLevel) {
+ if (this.experiment && this.experiment.additionalInfo) {
return this.experiment.additionalInfo.defaultObservationLevel;
}
return null;
From 036c0f7fa17c76eca673c80d038feb437fe1eee3 Mon Sep 17 00:00:00 2001
From: mlm483 <128052931+mlm483@users.noreply.github.com>
Date: Wed, 5 Jun 2024 16:17:33 -0400
Subject: [PATCH 4/9] [BI-2109] - updated UI for multiple dynamic datasets
---
src/breeding-insight/dao/ExperimentDAO.ts | 16 ++++++++
src/breeding-insight/model/DatasetMetadata.ts | 35 ++++++++++++++++++
src/breeding-insight/model/DatasetModel.ts | 1 -
.../model/ExperimentDatasetOption.ts | 1 +
.../service/ExperimentService.ts | 8 ++++
.../ExperimentObservationsDownloadModal.vue | 1 +
.../ExperimentsObservationsTable.vue | 14 ++++++-
src/router/index.ts | 7 ++--
.../ExperimentDetails.vue | 37 +++++++++++++++----
src/views/import/Dataset.vue | 6 ++-
10 files changed, 111 insertions(+), 15 deletions(-)
create mode 100644 src/breeding-insight/model/DatasetMetadata.ts
diff --git a/src/breeding-insight/dao/ExperimentDAO.ts b/src/breeding-insight/dao/ExperimentDAO.ts
index 381e7b5ea..f937c5f2e 100644
--- a/src/breeding-insight/dao/ExperimentDAO.ts
+++ b/src/breeding-insight/dao/ExperimentDAO.ts
@@ -20,6 +20,7 @@ import * as api from "@/util/api";
import {Result, ResultGenerator} from "@/breeding-insight/model/Result";
import {Trial} from "@/breeding-insight/model/Trial.ts";
import {DatasetModel} from "@/breeding-insight/model/DatasetModel";
+import {DatasetMetadata} from "@/breeding-insight/model/DatasetMetadata";
export class ExperimentDAO {
@@ -39,6 +40,21 @@ export class ExperimentDAO {
}
}
+ static async getDatasetMetadata(programId: string, experimentId: string): Promise> {
+ const config: any = {};
+ config.url = `${process.env.VUE_APP_BI_API_V1_PATH}/programs/${programId}/experiments/${experimentId}/datasets`;
+ config.method = 'get';
+ config.programId = programId;
+ config.experimentId = experimentId;
+ try {
+ const res = await api.call(config) as Response;
+ let { result } = res.data;
+ return ResultGenerator.success(result);
+ } catch (error) {
+ return ResultGenerator.err(error);
+ }
+ }
+
static async getDatasetById(programId: string, experimentId: string, datasetId: string, stats: boolean): Promise> {
const config: any = {};
config.url = `${process.env.VUE_APP_BI_API_V1_PATH}/programs/${programId}/experiments/${experimentId}/dataset/${datasetId}`;
diff --git a/src/breeding-insight/model/DatasetMetadata.ts b/src/breeding-insight/model/DatasetMetadata.ts
new file mode 100644
index 000000000..932e55935
--- /dev/null
+++ b/src/breeding-insight/model/DatasetMetadata.ts
@@ -0,0 +1,35 @@
+/*
+ * 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 {Observation} from "@/breeding-insight/model/Observation";
+import {ObservationUnit} from "@/breeding-insight/model/ObservationUnit";
+import {ObservationVariable} from "@/breeding-insight/model/ObservationVariable";
+
+export class DatasetMetadata {
+ id: string;
+ name: string;
+ level: number;
+
+ constructor(id: string,
+ name: string,
+ level: number
+ ) {
+ this.id = id;
+ this.name = name;
+ this.level = level;
+ }
+}
\ No newline at end of file
diff --git a/src/breeding-insight/model/DatasetModel.ts b/src/breeding-insight/model/DatasetModel.ts
index 1acd5016b..37d5abe82 100644
--- a/src/breeding-insight/model/DatasetModel.ts
+++ b/src/breeding-insight/model/DatasetModel.ts
@@ -28,7 +28,6 @@ export class DatasetModel {
additionalInfo?: any;
-
constructor(id: string,
experimentId: string,
data: Observation[],
diff --git a/src/breeding-insight/model/ExperimentDatasetOption.ts b/src/breeding-insight/model/ExperimentDatasetOption.ts
index 048b4e301..c1a636f41 100644
--- a/src/breeding-insight/model/ExperimentDatasetOption.ts
+++ b/src/breeding-insight/model/ExperimentDatasetOption.ts
@@ -17,6 +17,7 @@
import {SelectOption} from "@/breeding-insight/model/SelectOption";
+// TODO: update - this needs to be dynamic.
export class ExperimentDatasetOption implements SelectOption {
static observations = new ExperimentDatasetOption("Observation Dataset", "observations");
diff --git a/src/breeding-insight/service/ExperimentService.ts b/src/breeding-insight/service/ExperimentService.ts
index ab8ca5ddf..36556dba2 100644
--- a/src/breeding-insight/service/ExperimentService.ts
+++ b/src/breeding-insight/service/ExperimentService.ts
@@ -19,6 +19,7 @@ import {ExperimentDAO} from "@/breeding-insight/dao/ExperimentDAO";
import {Trial} from "@/breeding-insight/model/Trial.ts";
import {Result, ResultGenerator} from "@/breeding-insight/model/Result";
import {DatasetModel} from "@/breeding-insight/model/DatasetModel";
+import {DatasetMetadata} from "@/breeding-insight/model/DatasetMetadata";
export class ExperimentService {
@@ -42,4 +43,11 @@ export class ExperimentService {
}
return await ExperimentDAO.createSubEntityDataset(programId, experimentId, name, repeatedMeasures);
}
+
+ static async getDatasetMetadata(programId: string, experimentId: string): Promise> {
+ if (!programId) {
+ return ResultGenerator.err(new Error('Missing or invalid program id'));
+ }
+ return await ExperimentDAO.getDatasetMetadata(programId, experimentId);
+ }
}
diff --git a/src/components/experiments/ExperimentObservationsDownloadModal.vue b/src/components/experiments/ExperimentObservationsDownloadModal.vue
index 8083298e1..a8128c27a 100644
--- a/src/components/experiments/ExperimentObservationsDownloadModal.vue
+++ b/src/components/experiments/ExperimentObservationsDownloadModal.vue
@@ -191,6 +191,7 @@ export default class ExperimentObservationsDownloadModal extends Vue {
private fileOptions: ExperimentExportOptions = new ExperimentExportOptions();
private showEnvironmentsValidationError: boolean = false;
private fileExtensionOptions: object[] = Object.values(FileTypeOption);
+ // TODO: make this a dynamic set of datasets available for the experiment.
private datasetOptions: object[] = Object.values(ExperimentDatasetOption);
private environmentOptions: object[] = [];
private loadingStudyOptionsComplete: boolean = false;
diff --git a/src/components/experiments/ExperimentsObservationsTable.vue b/src/components/experiments/ExperimentsObservationsTable.vue
index 5f55f5a85..406d5eaf2 100644
--- a/src/components/experiments/ExperimentsObservationsTable.vue
+++ b/src/components/experiments/ExperimentsObservationsTable.vue
@@ -42,7 +42,7 @@
v-on:search="initSearch"
>
-
+
{{ props.row.data.trialName }}
@@ -95,6 +95,7 @@ import {PaginationController} from "@/breeding-insight/model/view_models/Paginat
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";
@Component({
mixins: [validationMixin],
@@ -192,6 +193,17 @@ export default class ExperimentsObservationsTable extends Vue {
}
}
+ // TODO: move to utilitiy?
+ getDefaultDataset(experiment: Trial): DatasetMetadata | null {
+ // Get default observation level.
+ if (experiment.additionalInfo !== null)
+ {
+ // One and only one top level dataset is always expected, and it will have level = 0.
+ return experiment.additionalInfo.datasets.find((x: DatasetMetadata) => x.level == 0) || null;
+ }
+ return null;
+ }
+
getStatus(active: boolean){
if (active) {
return "active";
diff --git a/src/router/index.ts b/src/router/index.ts
index cfec7e57b..afbd08f38 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -351,14 +351,15 @@ const routes = [
layout: layouts.userSideBar
},
component: ExperimentDetails,
- redirect: (to: Route) => ({name: 'experiment_obs_dataset', params: {datasetId: 'observation', programId: to.params.programId, experimentId: to.params.experimentId}}),
+ // TODO: test redirect with datasetId: null.
+ redirect: (to: Route) => ({name: 'experiment_dataset', params: {datasetId: null, programId: to.params.programId, experimentId: to.params.experimentId}}),
beforeEnter: processProgramNavigation,
children: [
{
path: 'dataset/:datasetId',
- name: 'experiment_obs_dataset',
+ name: 'experiment_dataset',
meta: {
- title: 'Observation Dataset',
+ title: `Datasets`,
layout: layouts.userSideBar
},
component: Dataset,
diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue
index 24939c375..e9b78128a 100644
--- a/src/views/experiments-and-observations/ExperimentDetails.vue
+++ b/src/views/experiments-and-observations/ExperimentDetails.vue
@@ -88,7 +88,7 @@
@@ -121,6 +121,7 @@ import ActionMenu from "@/components/layouts/menus/ActionMenu.vue";
import {ActionMenuItem} from "@/breeding-insight/model/ActionMenuItem";
import ExperimentObservationsDownloadModal from "@/components/experiments/ExperimentObservationsDownloadModal.vue";
import SubEntityDatasetModal from "@/components/modals/SubEntityDatasetModal.vue";
+import {DatasetMetadata} from "@/breeding-insight/model/DatasetMetadata";
@Component({
components: {
@@ -144,6 +145,7 @@ export default class ExperimentDetails extends ProgramsBase {
private experimentLoading: boolean = true;
private downloadModalActive: boolean = false;
private subEntityModalActive: boolean = false;
+ private datasetMetadata: DatasetMetadata[] = [];
private actions: ActionMenuItem[] = [
new ActionMenuItem('experiment-import-file', 'import-file', 'Import file'),
@@ -153,6 +155,7 @@ export default class ExperimentDetails extends ProgramsBase {
mounted () {
this.getExperiment();
+ this.getDatasetMetadata();
}
private importFile() {
@@ -170,6 +173,7 @@ export default class ExperimentDetails extends ProgramsBase {
private createSubEntityDataset(datasetName: string, repeatedMeasures: number): boolean {
// TODO: implement exception handling!
+ // TODO: improve UX - don't close modal without any indication.
console.log("createSubEntityDataset invoked with arguments: datasetName=" + datasetName + ", repeatedMeasures=" + repeatedMeasures);
ExperimentService.createSubEntityDataset(this.activeProgram!.id!, this.experimentUUID, datasetName, repeatedMeasures);
return true;
@@ -210,21 +214,21 @@ export default class ExperimentDetails extends ProgramsBase {
// return this.experiment.additionalInfo.environmentsCount;
// }
- // The options to make available in the autocomplete.
- get datasetNameOptions(): string[] {
- // TODO: implement!
- return ['Plot', 'Plant', 'Leaf']
- }
-
// The datasets that exist for this experiment already.
get datasets(): string[] | null {
- console.log(this.experiment.additionalInfo.datasets);
if (this.experiment && this.experiment.additionalInfo) {
return this.experiment.additionalInfo.datasets;
}
return null;
}
+ get datasetNameOptions(): String[] | null {
+ if (this.datasetMetadata) {
+ return this.datasetMetadata.map((x) => x.name);
+ }
+ return null;
+ }
+
get experimentObservationUnit(): string | null {
if (this.experiment && this.experiment.additionalInfo) {
return this.experiment.additionalInfo.defaultObservationLevel;
@@ -249,5 +253,22 @@ export default class ExperimentDetails extends ProgramsBase {
this.experimentLoading = false;
}
}
+
+ // TODO: add and test @Watch('$route').
+ // Get metadata for all datasets available in this experiment.
+ async getDatasetMetadata(): string[] {
+ try {
+ const response: Result = await ExperimentService.getDatasetMetadata(this.activeProgram!.id!, this.experimentUUID, true);
+ if (response.isErr()) {
+ throw response.value;
+ }
+ console.log(response.value);
+ this.datasetMetadata = response.value;
+ } catch (err) {
+ // Display error that experiment cannot be loaded
+ this.$emit('show-error-notification', 'Error while trying to load datasets');
+ throw err;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/views/import/Dataset.vue b/src/views/import/Dataset.vue
index fa0766b3e..fcd30022f 100644
--- a/src/views/import/Dataset.vue
+++ b/src/views/import/Dataset.vue
@@ -307,6 +307,7 @@ import {Metadata} from "@/breeding-insight/model/BiResponse";
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";
@Component({
components: {
@@ -615,8 +616,9 @@ export default class Dataset extends ProgramsBase {
if (experimentResult.isErr()) throw experimentResult.value;
this.experiment = experimentResult.value;
- if (this.datasetId === 'observation') {
- this.resultDatasetId = this.experiment.additionalInfo.observationDatasetId;
+ if (this.datasetId === null) {
+ // Get top level dataset id.
+ this.resultDatasetId = this.experiment.additionalInfo.datasets.find((x: DatasetMetadata) => x.level == 0).id || null;
} else {
this.resultDatasetId = this.datasetId;
}
From 65bf33a08e0622c9d56b6929187c14bd1847cb84 Mon Sep 17 00:00:00 2001
From: mlm483 <128052931+mlm483@users.noreply.github.com>
Date: Fri, 7 Jun 2024 16:19:09 -0400
Subject: [PATCH 5/9] [BI-2109] - improved UI based on feedback
---
src/components/modals/SubEntityDatasetModal.vue | 2 +-
.../experiments-and-observations/ExperimentDetails.vue | 7 +++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/components/modals/SubEntityDatasetModal.vue b/src/components/modals/SubEntityDatasetModal.vue
index f7241c4e6..432edb6a1 100644
--- a/src/components/modals/SubEntityDatasetModal.vue
+++ b/src/components/modals/SubEntityDatasetModal.vue
@@ -38,7 +38,7 @@
id="dataset-name-autocomplete"
v-model="datasetName"
v-bind:options="datasetNameOptions"
- v-bind:field-name="'Dataset Name'"
+ v-bind:field-name="'Sub-Entity Name'"
v-bind:field-help="'Create new or reuse a previously described sub-observation unit.'"
v-bind:show-label="true"
/>
diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue
index e9b78128a..8cd27ad32 100644
--- a/src/views/experiments-and-observations/ExperimentDetails.vue
+++ b/src/views/experiments-and-observations/ExperimentDetails.vue
@@ -92,7 +92,7 @@
tag="li"
active-class="is-active"
>
- {{ dataset.name }} Dataset
+ {{ dataset.name }}
@@ -223,9 +223,8 @@ export default class ExperimentDetails extends ProgramsBase {
}
get datasetNameOptions(): String[] | null {
- if (this.datasetMetadata) {
- return this.datasetMetadata.map((x) => x.name);
- }
+ // TODO: [BI-2182] fetch and return all sub-entity names for experiments in this program, excluding the current experiment.
+ // TODO: [BI-2182] exclude top level dataset names.
return null;
}
From fac5b0eaf83171ad6353dbb39f7f66c8cf78d61d Mon Sep 17 00:00:00 2001
From: mlm483 <128052931+mlm483@users.noreply.github.com>
Date: Mon, 10 Jun 2024 13:13:31 -0400
Subject: [PATCH 6/9] [BI-2109] - added watch
---
src/views/experiments-and-observations/ExperimentDetails.vue | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/views/experiments-and-observations/ExperimentDetails.vue b/src/views/experiments-and-observations/ExperimentDetails.vue
index 8cd27ad32..78eaee5b1 100644
--- a/src/views/experiments-and-observations/ExperimentDetails.vue
+++ b/src/views/experiments-and-observations/ExperimentDetails.vue
@@ -255,6 +255,7 @@ export default class ExperimentDetails extends ProgramsBase {
// TODO: add and test @Watch('$route').
// Get metadata for all datasets available in this experiment.
+ @Watch('$route')
async getDatasetMetadata(): string[] {
try {
const response: Result = await ExperimentService.getDatasetMetadata(this.activeProgram!.id!, this.experimentUUID, true);
From eb79e7282152db0bb49c65636f59b2e3fde6779a Mon Sep 17 00:00:00 2001
From: mlm483 <128052931+mlm483@users.noreply.github.com>
Date: Mon, 10 Jun 2024 18:06:40 -0400
Subject: [PATCH 7/9] [BI-2109] - improved UI
---
src/assets/scss/main.scss | 13 ++
.../model/SubEntityDatasetNewRequest.ts | 31 ++++
.../service/ExperimentService.ts | 5 +-
.../ExperimentsObservationsTable.vue | 2 +-
src/components/forms/BaseFieldWrapper.vue | 3 +
.../modals/SubEntityDatasetModal.vue | 140 ++++++++++--------
.../ExperimentDetails.vue | 22 +--
7 files changed, 141 insertions(+), 75 deletions(-)
create mode 100644 src/breeding-insight/model/SubEntityDatasetNewRequest.ts
diff --git a/src/assets/scss/main.scss b/src/assets/scss/main.scss
index fdc4c89c4..cccc8083a 100644
--- a/src/assets/scss/main.scss
+++ b/src/assets/scss/main.scss
@@ -84,6 +84,8 @@ $table-striped-row-even-hover-background-color:$link-light;
$medium-modal-content-width: $modal-content-width * 1.4;
$medium-modal-body-padding: 0 3em 2em 3em;
+$large-modal-content-width: $modal-content-width * 1.8;
+
//$margin-right: 2 rem;
// Import buefy before bulma
@@ -909,6 +911,17 @@ tr:nth-child(odd) td.db-filled {
}
}
+.sub-entity-dataset-modal {
+ .modal {
+ .modal-card {
+ width: $large-modal-content-width;
+ .modal-card-body {
+ padding: $medium-modal-body-padding;
+ }
+ }
+ }
+}
+
.content {
.pagination-list {
margin-top: 0;
diff --git a/src/breeding-insight/model/SubEntityDatasetNewRequest.ts b/src/breeding-insight/model/SubEntityDatasetNewRequest.ts
new file mode 100644
index 000000000..4f5c384d1
--- /dev/null
+++ b/src/breeding-insight/model/SubEntityDatasetNewRequest.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 {Observation} from "@/breeding-insight/model/Observation";
+import {ObservationUnit} from "@/breeding-insight/model/ObservationUnit";
+import {ObservationVariable} from "@/breeding-insight/model/ObservationVariable";
+
+export class SubEntityDatasetNewRequest {
+ name: string;
+ repeatedMeasures: number;
+
+
+ constructor(name: string, repeatedMeasures: string) {
+ this.name = name;
+ this.repeatedMeasures = repeatedMeasures;
+ }
+}
\ No newline at end of file
diff --git a/src/breeding-insight/service/ExperimentService.ts b/src/breeding-insight/service/ExperimentService.ts
index 36556dba2..9ee35c1be 100644
--- a/src/breeding-insight/service/ExperimentService.ts
+++ b/src/breeding-insight/service/ExperimentService.ts
@@ -20,6 +20,7 @@ import {Trial} from "@/breeding-insight/model/Trial.ts";
import {Result, ResultGenerator} from "@/breeding-insight/model/Result";
import {DatasetModel} from "@/breeding-insight/model/DatasetModel";
import {DatasetMetadata} from "@/breeding-insight/model/DatasetMetadata";
+import {SubEntityDatasetNewRequest} from "@/breeding-insight/model/SubEntityDatasetNewRequest";
export class ExperimentService {
@@ -37,11 +38,11 @@ export class ExperimentService {
return await ExperimentDAO.getDatasetById(programId,experimentId, datasetId, true);
}
- static async createSubEntityDataset(programId: string, experimentId: string, name: string, repeatedMeasures: number): Promise> {
+ static async createSubEntityDataset(programId: string, experimentId: string, subEntityRequest: SubEntityDatasetNewRequest): Promise> {
if (!programId) {
return ResultGenerator.err(new Error('Missing or invalid program id'));
}
- return await ExperimentDAO.createSubEntityDataset(programId, experimentId, name, repeatedMeasures);
+ return await ExperimentDAO.createSubEntityDataset(programId, experimentId, subEntityRequest.name, subEntityRequest.repeatedMeasures);
}
static async getDatasetMetadata(programId: string, experimentId: string): Promise> {
diff --git a/src/components/experiments/ExperimentsObservationsTable.vue b/src/components/experiments/ExperimentsObservationsTable.vue
index 406d5eaf2..d800b5b2f 100644
--- a/src/components/experiments/ExperimentsObservationsTable.vue
+++ b/src/components/experiments/ExperimentsObservationsTable.vue
@@ -58,7 +58,7 @@
- {{ dataset.name }}
+ {{ dataset.name }}
diff --git a/src/components/forms/BaseFieldWrapper.vue b/src/components/forms/BaseFieldWrapper.vue
index 7f9a4b68a..d412a920d 100644
--- a/src/components/forms/BaseFieldWrapper.vue
+++ b/src/components/forms/BaseFieldWrapper.vue
@@ -108,6 +108,9 @@
case 'alpha':
validationMap['message'] = `${this.fieldName} must use only alphabetic characters.`;
break;
+ case 'between':
+ validationMap['message'] = `${this.fieldName} must be between ${this.validations.$params.between.min} and ${this.validations.$params.between.max}.`;
+ break;
default:
// For now assume other possibility is a specific format
validationMap['message'] = `${this.fieldName} must be in ${validation} format`;
diff --git a/src/components/modals/SubEntityDatasetModal.vue b/src/components/modals/SubEntityDatasetModal.vue
index 432edb6a1..5c7a04f55 100644
--- a/src/components/modals/SubEntityDatasetModal.vue
+++ b/src/components/modals/SubEntityDatasetModal.vue
@@ -17,62 +17,65 @@
-
-
-
-
- Prepare a dataset for repeated observations within {{ defaultObservationLevel }}.
+
+
+
+
+ {{ modalTitle }}
+
-
-
-
-
+
+
+
+
+
+ Prepare a dataset for repeated observations within {{ defaultObservationLevel }}.
+