Merge pull request #13772 from davelopez/restore_homogeneous_hdca_indicator

Restore homogeneous dataset collection indicator
This commit is contained in:
Björn Grüning
2022-04-22 18:58:26 +02:00
committed by GitHub
8 changed files with 109 additions and 99 deletions
@@ -11,23 +11,50 @@ describe("CollectionDescription", () => {
wrapper = mount(CollectionDescription, {
propsData: {
collectionType: "list",
elementCount: 10,
},
localVue,
});
});
it("check basics", async () => {
const details = wrapper.findAll("span");
expect(details.at(0).text()).toBe("a list");
expect(details.at(1).text()).toBe("with 10 items");
await wrapper.setProps({ elementCount: 1 });
expect(details.at(1).text()).toBe("with 1 item");
await wrapper.setProps({ collectionType: "paired" });
expect(details.at(0).text()).toBe("a dataset pair");
it("should display expected heterogeneous descriptions", async () => {
const HETEROGENEOUS_DATATYPES = ["txt", "csv", "tabular"];
await wrapper.setProps({ elementCount: 1, elementsDatatypes: HETEROGENEOUS_DATATYPES });
expect(wrapper.text()).toBe("a list with 1 dataset");
await wrapper.setProps({ elementCount: 2, collectionType: "paired" });
expect(wrapper.text()).toBe("a pair with 2 datasets");
await wrapper.setProps({ elementCount: 10, collectionType: "list" });
expect(wrapper.text()).toBe("a list with 10 datasets");
await wrapper.setProps({ collectionType: "list:paired" });
expect(details.at(0).text()).toBe("a list of pairs");
expect(wrapper.text()).toBe("a list with 10 pairs");
await wrapper.setProps({ collectionType: "list:list" });
expect(wrapper.text()).toBe("a list with 10 lists");
await wrapper.setProps({ collectionType: "other" });
expect(details.at(0).text()).toBe("a nested list");
expect(wrapper.text()).toBe("a nested list with 10 dataset collections");
});
it("should display expected homogeneous descriptions", async () => {
const EXPECTED_HOMOGENEOUS_DATATYPE = "tabular";
await wrapper.setProps({ elementCount: 1, elementsDatatypes: [EXPECTED_HOMOGENEOUS_DATATYPE] });
expect(wrapper.text()).toBe(`a list with 1 ${EXPECTED_HOMOGENEOUS_DATATYPE} dataset`);
await wrapper.setProps({ elementCount: 2, collectionType: "paired" });
expect(wrapper.text()).toBe(`a pair with 2 ${EXPECTED_HOMOGENEOUS_DATATYPE} datasets`);
await wrapper.setProps({ elementCount: 10, collectionType: "list" });
expect(wrapper.text()).toBe(`a list with 10 ${EXPECTED_HOMOGENEOUS_DATATYPE} datasets`);
await wrapper.setProps({ collectionType: "list:paired" });
expect(wrapper.text()).toBe(`a list with 10 ${EXPECTED_HOMOGENEOUS_DATATYPE} pairs`);
await wrapper.setProps({ collectionType: "list:list" });
expect(wrapper.text()).toBe(`a list with 10 ${EXPECTED_HOMOGENEOUS_DATATYPE} lists`);
await wrapper.setProps({ collectionType: "other" });
expect(wrapper.text()).toBe(`a nested list with 10 ${EXPECTED_HOMOGENEOUS_DATATYPE} dataset collections`);
});
});
@@ -1,8 +1,6 @@
<template>
<h6 class="description mt-1">
<span>a {{ collectionLabel | localize }}</span>
<span v-if="elementCount == 1">with 1 item</span>
<span v-else-if="elementCount > 1">with {{ elementCount }} items</span>
a {{ collectionLabel }} with {{ elementCount }}<b>{{ homogeneousDatatype }}</b> {{ pluralizedItem }}
</h6>
</template>
@@ -10,21 +8,55 @@
export default {
props: {
collectionType: { type: String, required: true },
elementCount: { type: Number, required: true },
elementCount: { type: Number, required: false, default: undefined },
elementsDatatypes: { type: Array, required: false, default: () => [] },
},
data() {
return {
labels: {
list: "list",
paired: "dataset pair",
"list:paired": "list of pairs",
"list:paired": "list",
"list:list": "list",
paired: "pair",
},
};
},
computed: {
/**@return {String} */
collectionLabel() {
return this.labels[this.collectionType] || "nested list";
},
/**@return {Boolean} */
hasSingleElement() {
return this.elementCount === 1;
},
/**@return {Boolean} */
isHomogeneous() {
return this.elementsDatatypes.length === 1;
},
/**@return {String} */
homogeneousDatatype() {
return this.isHomogeneous ? ` ${this.elementsDatatypes[0]}` : "";
},
/**@return {String} */
pluralizedItem() {
if (this.collectionType === "list:list") {
return this.pluralize("list");
}
if (this.collectionType === "list:paired") {
return this.pluralize("pair");
}
if (!Object.keys(this.labels).includes(this.collectionType)) {
//Any other kind of nested collection
return this.pluralize("dataset collection");
}
return this.pluralize("dataset");
},
},
methods: {
pluralize(word) {
return this.hasSingleElement ? word : `${word}s`;
},
},
};
</script>
@@ -32,7 +32,8 @@
<CollectionDescription
v-if="!isDataset"
:collection-type="item.collection_type"
:element-count="item.element_count" />
:element-count="item.element_count"
:elements-datatypes="item.elements_datatypes" />
<div v-if="item.tags && item.tags.length > 0" class="nametags">
<Nametag v-for="tag in item.tags" :key="tag" :tag="tag" />
</div>
@@ -7,7 +7,10 @@
@save="$emit('update:dsc', $event)">
<template v-slot:name>
<h3 data-description="collection name display" v-short="dsc.name || 'Collection'" />
<CollectionDescription :item="dsc" />
<CollectionDescription
:collection-type="dsc.collection_type"
:element-count="dsc.element_count"
:elements-datatypes="dsc.elements_datatypes" />
</template>
</Details>
</template>
@@ -1,40 +0,0 @@
{
"job_source_id": null,
"populated_state": "ok",
"type": "collection",
"hid": 9,
"name": "Heterogeneous list",
"url": "/api/histories/4ff6f47412c3e65e/contents/dataset_collections/5a1cff6882ddb5b2",
"element_count": 4,
"job_source_type": null,
"history_id": "4ff6f47412c3e65e",
"id": "5a1cff6882ddb5b2",
"type_id": "dataset_collection-5a1cff6882ddb5b2",
"create_time": "2020-06-26T14:22:58.435340",
"collection_type": "list",
"history_content_type": "dataset_collection",
"populated_state_message": null,
"job_state_summary": {
"error": 0,
"upload": 0,
"queued": 0,
"all_jobs": 0,
"paused": 0,
"ok": 0,
"new": 0,
"waiting": 0,
"failed": 0,
"deleted": 0,
"resubmitted": 0,
"running": 0,
"deleted_new": 0
},
"contents_url": "/api/dataset_collections/5a1cff6882ddb5b2/contents/f09437b8822035f7",
"tags": [],
"visible": true,
"deleted": false,
"populated": true,
"update_time": "2020-06-26T14:22:58.435348",
"collection_id": 23,
"elements_datatypes": ["txt", "csv", "tabular"]
}
@@ -1,40 +0,0 @@
{
"job_source_id": null,
"populated_state": "ok",
"type": "collection",
"hid": 9,
"name": "Homogeneous list",
"url": "/api/histories/4ff6f47412c3e65e/contents/dataset_collections/5a1cff6882ddb5b2",
"element_count": 4,
"job_source_type": null,
"history_id": "4ff6f47412c3e65e",
"id": "5a1cff6882ddb5b2",
"type_id": "dataset_collection-5a1cff6882ddb5b2",
"create_time": "2020-06-26T14:22:58.435340",
"collection_type": "list",
"history_content_type": "dataset_collection",
"populated_state_message": null,
"job_state_summary": {
"error": 0,
"upload": 0,
"queued": 0,
"all_jobs": 0,
"paused": 0,
"ok": 0,
"new": 0,
"waiting": 0,
"failed": 0,
"deleted": 0,
"resubmitted": 0,
"running": 0,
"deleted_new": 0
},
"contents_url": "/api/dataset_collections/5a1cff6882ddb5b2/contents/f09437b8822035f7",
"tags": [],
"visible": true,
"deleted": false,
"populated": true,
"update_time": "2020-06-26T14:22:58.435348",
"collection_id": 23,
"elements_datatypes": ["txt"]
}
@@ -971,6 +971,7 @@ class HistoriesContentsService(ServiceBase):
f"Invalid filter found. When requesting stats, please avoid filtering by {non_orm_filter_keys}"
)
serialization_params = self._handle_extra_serialization_for_media_type(serialization_params, accept)
filter_query_params.order = filter_query_params.order or "hid-asc"
order_by = self.build_order_by(self.history_contents_manager, filter_query_params.order)
contents = self.history_contents_manager.contents(
@@ -999,6 +1000,18 @@ class HistoriesContentsService(ServiceBase):
return HistoryContentsWithStatsResult.construct(contents=items, stats=stats)
return HistoryContentsResult.construct(__root__=items)
def _handle_extra_serialization_for_media_type(
self,
serialization_params: SerializationParams,
request_media_type: str,
) -> SerializationParams:
"""According to the requested media type the response may include extra information."""
if request_media_type == HistoryContentsWithStatsResult.__accept_type__:
if not serialization_params.keys:
serialization_params.keys = []
serialization_params.keys.append("elements_datatypes")
return serialization_params
def _serialize_legacy_content_item(
self,
trans,
@@ -1138,6 +1138,20 @@ class HistoryContentsApiBulkOperationTestCase(ApiTestCase):
)
self._assert_status_code_is(response, 400)
def test_index_with_stats_has_extra_serialization(self):
expected_extra_keys_in_collections = ["elements_datatypes"]
with self.dataset_populator.test_history() as history_id:
self._create_collection_in_history(history_id)
response = self._get_contents_with_stats(
history_id,
search_query="&q=history_content_type-eq&qv=dataset_collection",
)
self._assert_status_code_is(response, 200)
contents_with_stats = response.json()
assert contents_with_stats["contents"]
collection = contents_with_stats["contents"][0]
self._assert_has_keys(collection, *expected_extra_keys_in_collections)
def _get_contents_with_stats(self, history_id: str, search_query: str = ""):
headers = {"accept": "application/vnd.galaxy.history.contents.stats+json"}
search_response = self._get(f"histories/{history_id}/contents?v=dev{search_query}", headers=headers)