Skip to content

Commit

Permalink
Merge pull request #16752 from davelopez/migrate_collection_attribute…
Browse files Browse the repository at this point in the history
…s_store_pinia

Migrate `collection attributes` store to Pinia
  • Loading branch information
dannon authored Oct 11, 2023
2 parents 351ba37 + c4529f7 commit cd287a0
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 48 deletions.
17 changes: 5 additions & 12 deletions client/src/components/Collections/common/CollectionEditView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import { errorMessageAsString } from "utils/simple-error";
import Vue from "vue";
import { useConfig } from "@/composables/config";
import { useCollectionAttributesStore } from "@/stores/collectionAttributesStore";
import { useHistoryStore } from "@/stores/historyStore";
import { DatatypesProvider, DbKeyProvider, SuitableConvertersProvider } from "../../providers";
Expand Down Expand Up @@ -101,7 +102,6 @@ export default {
},
data: function () {
return {
attributesData: {},
errorMessage: null,
jobError: null,
noQuotaIncrease: true,
Expand All @@ -114,28 +114,21 @@ export default {
},
computed: {
...mapState(useHistoryStore, ["currentHistoryId"]),
...mapState(useCollectionAttributesStore, ["getAttributes"]),
attributesData() {
return this.getAttributes(this.collectionId);
},
databaseKeyFromElements: function () {
return this.attributesData.dbkey;
},
datatypeFromElements: function () {
return this.attributesData.extension;
},
},
created() {
this.getCollectionDataAndAttributes();
},
methods: {
updateInfoMessage: function (strMessage) {
this.infoMessage = strMessage;
},
getCollectionDataAndAttributes: async function () {
let attributesGet = this.$store.getters.getCollectionAttributes(this.collectionId);
if (attributesGet == null) {
await this.$store.dispatch("fetchCollectionAttributes", this.collectionId);
attributesGet = this.$store.getters.getCollectionAttributes(this.collectionId);
}
this.attributesData = attributesGet;
},
clickedSave: function (attribute, newValue) {
const url = prependPath(`/api/dataset_collections/${this.collectionId}/copy`);
const data = {};
Expand Down
33 changes: 0 additions & 33 deletions client/src/store/collectionAttributesStore.js

This file was deleted.

2 changes: 0 additions & 2 deletions client/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import Vuex from "vuex";
import createCache from "vuex-cache";
import VuexPersistence from "vuex-persist";

import { collectionAttributesStore } from "./collectionAttributesStore";
import { datasetExtFilesStore } from "./datasetExtFilesStore";
import { datasetPathDestinationStore } from "./datasetPathDestinationStore";
import { gridSearchStore } from "./gridSearchStore";
Expand Down Expand Up @@ -45,7 +44,6 @@ export function createStore() {
const storeConfig = {
plugins: [createCache(), panelsPersistence.plugin],
modules: {
collectionAttributesStore: collectionAttributesStore,
destinationParameters: jobDestinationParametersStore,
datasetExtFiles: datasetExtFilesStore,
datasetPathDestination: datasetPathDestinationStore,
Expand Down
55 changes: 55 additions & 0 deletions client/src/stores/collectionAttributesStore.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import flushPromises from "flush-promises";
import { createPinia, setActivePinia } from "pinia";

import { mockFetcher } from "@/schema/__mocks__";
import { DatasetCollectionAttributes } from "@/stores/services";

import { useCollectionAttributesStore } from "./collectionAttributesStore";

jest.mock("@/schema");

const FAKE_HDCA_ID = "123";

const FAKE_ATTRIBUTES: DatasetCollectionAttributes = {
dbkey: "hg19",
extension: "bed",
model_class: "HistoryDatasetCollectionAssociation",
dbkeys: ["hg19", "hg38"],
extensions: ["bed", "vcf"],
tags: ["tag1", "tag2"],
};

const fetchCollectionAttributes = jest.fn().mockResolvedValue({ data: FAKE_ATTRIBUTES });

describe("collectionAttributesStore", () => {
beforeEach(() => {
setActivePinia(createPinia());
mockFetcher.path("/api/dataset_collections/{id}/attributes").method("get").mock(fetchCollectionAttributes);
});

it("should fetch attributes and store them", async () => {
const store = useCollectionAttributesStore();
expect(store.storedAttributes[FAKE_HDCA_ID]).toBeUndefined();
expect(store.isLoadingAttributes(FAKE_HDCA_ID)).toBeFalsy();

store.getAttributes(FAKE_HDCA_ID);
// getAttributes will trigger a fetch if the attributes are not stored
expect(store.isLoadingAttributes(FAKE_HDCA_ID)).toBeTruthy();
await flushPromises();
expect(store.isLoadingAttributes(FAKE_HDCA_ID)).toBeFalsy();

expect(store.storedAttributes[FAKE_HDCA_ID]).toEqual(FAKE_ATTRIBUTES);
expect(fetchCollectionAttributes).toHaveBeenCalled();
});

it("should not fetch attributes if already stored", async () => {
const store = useCollectionAttributesStore();

store.storedAttributes[FAKE_HDCA_ID] = FAKE_ATTRIBUTES;

const result = store.getAttributes(FAKE_HDCA_ID);

expect(result).toEqual(FAKE_ATTRIBUTES);
expect(fetchCollectionAttributes).not.toHaveBeenCalled();
});
});
43 changes: 43 additions & 0 deletions client/src/stores/collectionAttributesStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { defineStore } from "pinia";
import { computed, del, ref, set } from "vue";

import { DatasetCollectionAttributes } from "./services";
import { fetchCollectionAttributes } from "./services/datasetCollection.service";

export const useCollectionAttributesStore = defineStore("collectionAttributesStore", () => {
const storedAttributes = ref<{ [key: string]: DatasetCollectionAttributes }>({});
const loadingAttributes = ref<{ [key: string]: boolean }>({});

const getAttributes = computed(() => {
return (hdcaId: string) => {
if (!storedAttributes.value[hdcaId]) {
set(storedAttributes.value, hdcaId, {});
fetchAttributes({ hdcaId });
}
return storedAttributes.value[hdcaId];
};
});

const isLoadingAttributes = computed(() => {
return (hdcaId: string) => {
return loadingAttributes.value[hdcaId] ?? false;
};
});

async function fetchAttributes(params: { hdcaId: string }) {
set(loadingAttributes.value, params.hdcaId, true);
try {
const attributes = await fetchCollectionAttributes(params);
set(storedAttributes.value, params.hdcaId, attributes);
return attributes;
} finally {
del(loadingAttributes.value, params.hdcaId);
}
}

return {
storedAttributes,
getAttributes,
isLoadingAttributes,
};
});
9 changes: 8 additions & 1 deletion client/src/stores/services/datasetCollection.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { fetcher } from "@/schema";

import { CollectionEntry, DCESummary, HDCADetailed, isHDCA } from ".";
import { CollectionEntry, DatasetCollectionAttributes, DCESummary, HDCADetailed, isHDCA } from ".";

const DEFAULT_LIMIT = 50;

Expand Down Expand Up @@ -53,3 +53,10 @@ export async function fetchElementsFromCollection(params: {
limit: params.limit ?? DEFAULT_LIMIT,
});
}

const getCollectionAttributes = fetcher.path("/api/dataset_collections/{id}/attributes").method("get").create();

export async function fetchCollectionAttributes(params: { hdcaId: string }): Promise<DatasetCollectionAttributes> {
const { data } = await getCollectionAttributes({ id: params.hdcaId, instance_type: "history" });
return data;
}
2 changes: 2 additions & 0 deletions client/src/stores/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export type HDCADetailed = components["schemas"]["HDCADetailed"];
*/
export type DCObject = components["schemas"]["DCObject"];

export type DatasetCollectionAttributes = components["schemas"]["DatasetCollectionAttributesResult"];

/**
* A SubCollection is a DatasetCollectionElement of type `dataset_collection`
* with additional information to simplify its handling.
Expand Down

0 comments on commit cd287a0

Please sign in to comment.