From 72b221fd8b787ccee08105252834bd2c8c3ed0b3 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Tue, 16 Aug 2022 12:15:16 +0200 Subject: [PATCH 01/26] add detailed edam_formats and edam_data apis --- lib/galaxy/datatypes/_schema.py | 26 +++++++++++++++++++ lib/galaxy/datatypes/registry.py | 10 ++++++++ lib/galaxy/managers/datatypes.py | 29 ++++++++++++++++++++++ lib/galaxy/tool_util/edam_util.py | 16 ++++++------ lib/galaxy/tool_util/toolbox/views/edam.py | 10 +++++--- lib/galaxy/webapps/galaxy/api/datatypes.py | 23 ++++++++++++++--- 6 files changed, 98 insertions(+), 16 deletions(-) diff --git a/lib/galaxy/datatypes/_schema.py b/lib/galaxy/datatypes/_schema.py index 50c1774b614..d9b7ea5cfaf 100644 --- a/lib/galaxy/datatypes/_schema.py +++ b/lib/galaxy/datatypes/_schema.py @@ -98,3 +98,29 @@ class DatatypeConverter(BaseModel): class DatatypeConverterList(BaseModel): __root__: List[DatatypeConverter] = Field(title="List of data type converters", default=[]) + + +class DatatypeEDAMDetails(BaseModel): + prefix_IRI: str = Field( + ..., # Mark this field as required + title="Prefix IRI", + description="The EDAM prefixed Resource Identifier", + example="format_1782", + ) + label: Optional[str] = Field( + title="Label", + description="The EDAM label", + example="NCBI gene report format", + ) + definition: Optional[str] = Field( + title="Definition", + description="The EDAM definition", + example="Entry (gene) format of the NCBI database.", + ) + + +class DatatypeEDAMDetailsDict(BaseModel): + __root__: Dict[str, DatatypeEDAMDetails] = Field( + title="Dict of EDAM details for formats", + default={}, + ) diff --git a/lib/galaxy/datatypes/registry.py b/lib/galaxy/datatypes/registry.py index 4ac590c55f1..ba061710bee 100644 --- a/lib/galaxy/datatypes/registry.py +++ b/lib/galaxy/datatypes/registry.py @@ -21,6 +21,7 @@ import yaml import galaxy.util from galaxy.util import RW_R__R__ from galaxy.util.bunch import Bunch +from galaxy.tool_util.edam_util import load_edam_tree from . import ( binary, coverage, @@ -46,9 +47,18 @@ class ConfigurationError(Exception): class Registry: def __init__(self, config=None): + edam_ontology_path = config.edam_toolbox_ontology_path + + edam = load_edam_tree( + None if not edam_ontology_path or not os.path.exists(edam_ontology_path) else edam_ontology_path, + "format_", + "data_", + ) + self.log = logging.getLogger(__name__) self.log.addHandler(logging.NullHandler()) self.config = config + self.edam = edam self.datatypes_by_extension = {} self.datatypes_by_suffix_inferences = {} self.mimetypes_by_extension = {} diff --git a/lib/galaxy/managers/datatypes.py b/lib/galaxy/managers/datatypes.py index 9b5a6450670..95c46e19d36 100644 --- a/lib/galaxy/managers/datatypes.py +++ b/lib/galaxy/managers/datatypes.py @@ -12,6 +12,7 @@ from galaxy.datatypes._schema import ( DatatypeDetails, DatatypesCombinedMap, DatatypesMap, + DatatypeEDAMDetailsDict, ) from galaxy.datatypes.data import Data from galaxy.datatypes.registry import Registry @@ -89,6 +90,34 @@ def view_converters(datatypes_registry: Registry) -> DatatypeConverterList: return parse_obj_as(DatatypeConverterList, converters) +def _get_edam_details(datatypes_registry: Registry, edam_ids: Dict[str, str]): + details_dict = {} + for (format, edam_iri) in edam_ids.items(): + edam_details = datatypes_registry.edam.get(edam_iri, {}) + + details_dict[format] = { + "prefix_IRI": edam_iri, + "label": edam_details.get("label", None), + "definition": edam_details.get("definition", None), + } + + return details_dict + + +def view_edam_formats(datatypes_registry: Registry, id_only: Optional[bool] = True) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: + if id_only: + return datatypes_registry.edam_formats + else: + return _get_edam_details(datatypes_registry, datatypes_registry.edam_formats) + + +def view_edam_data(datatypes_registry: Registry, id_only: Optional[bool] = True) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: + if id_only: + return datatypes_registry.edam_data + else: + return _get_edam_details(datatypes_registry, datatypes_registry.edam_data) + + __all__ = ( "DatatypeConverterList", "DatatypeDetails", diff --git a/lib/galaxy/tool_util/edam_util.py b/lib/galaxy/tool_util/edam_util.py index 26102b1ae37..da4d0560bbd 100644 --- a/lib/galaxy/tool_util/edam_util.py +++ b/lib/galaxy/tool_util/edam_util.py @@ -16,19 +16,19 @@ ROOT_OPERATION = "operation_0004" ROOT_TOPIC = "topic_0003" -def load_edam_tree(path: Optional[str] = None): +def load_edam_tree(path: Optional[str] = None, *included_terms: str): if path is not None: assert os.path.exists(path), f"Failed to load EDAM tabular data at [{path}] path does not exist." handle = open(path) else: assert ( tabular_stream is not None - ), "Failed to load optional import from edam-onotology package, install using [pip install edam-ontology]." + ), "Failed to load optional import from edam-ontology package, install using [pip install edam-ontology]." handle = tabular_stream() - return load_edam_tree_from_tsv_stream(handle) + return load_edam_tree_from_tsv_stream(handle, *included_terms) -def load_edam_tree_from_tsv_stream(tsv_stream: TextIO): +def load_edam_tree_from_tsv_stream(tsv_stream: TextIO, *included_terms: str): edam: Dict[str, Dict] = {} def _recurse_edam_parents(term, path=None): @@ -47,7 +47,7 @@ def load_edam_tree_from_tsv_stream(tsv_stream: TextIO): columns[field] = i is_first = False - defintion_column = columns["http://www.geneontology.org/formats/oboInOwl#hasDefinition"] + definition_column = columns["http://www.geneontology.org/formats/oboInOwl#hasDefinition"] term_column = columns["Class ID"] label_column = columns["Preferred Label"] parents_column = columns["Parents"] @@ -59,14 +59,14 @@ def load_edam_tree_from_tsv_stream(tsv_stream: TextIO): term_id = term[len(EDAM_PREFIX) :] - # Only care about formats and operations - if not (term_id.startswith("operation_") or term_id.startswith("topic_")): + # Only care about included terms + if (included_terms is not None) and not (term_id.startswith(included_terms)): continue parents = fields[parents_column].split("|") edam[term_id] = { "label": fields[label_column], - "definition": fields[defintion_column].strip('"'), + "definition": fields[definition_column].strip('"'), "parents": [x[len(EDAM_PREFIX) :] for x in parents if x.startswith(EDAM_PREFIX)], } diff --git a/lib/galaxy/tool_util/toolbox/views/edam.py b/lib/galaxy/tool_util/toolbox/views/edam.py index 89ec2fa1e49..8049e07a0f0 100644 --- a/lib/galaxy/tool_util/toolbox/views/edam.py +++ b/lib/galaxy/tool_util/toolbox/views/edam.py @@ -38,7 +38,9 @@ class EdamPanelMode(str, Enum): class EdamToolPanelView(ToolPanelView): def __init__(self, edam_ontology_path: Optional[str], mode: EdamPanelMode = EdamPanelMode.merged): edam = load_edam_tree( - None if not edam_ontology_path or not os.path.exists(edam_ontology_path) else edam_ontology_path + None if not edam_ontology_path or not os.path.exists(edam_ontology_path) else edam_ontology_path, + "operation_", + "topic_", ) self.edam = edam self.mode = mode @@ -162,15 +164,15 @@ class EdamToolPanelView(ToolPanelView): if mode == EdamPanelMode.merged: model_id = "ontology:edam_merged" name = "EDAM Operations and Topics" - description = "Tools are grouped using both annotated operation and topic information (if availabled)." + description = "Tools are grouped using both annotated operation and topic information (if available)." elif mode == EdamPanelMode.operations: model_id = "ontology:edam_operations" name = "EDAM Operations" - description = "Tools are grouped using annotated EDAM operation information (if availabled)." + description = "Tools are grouped using annotated EDAM operation information (if available)." elif mode == EdamPanelMode.topics: model_id = "ontology:edam_topics" name = "EDAM Topics" - description = "Tools are grouped using annotated EDAM topic information (if availabled)." + description = "Tools are grouped using annotated EDAM topic information (if available)." else: raise AssertionError(f"Invalid EDAM mode encountered {mode}") model_class = self.__class__.__name__ diff --git a/lib/galaxy/webapps/galaxy/api/datatypes.py b/lib/galaxy/webapps/galaxy/api/datatypes.py index c91f2bb90be..9e31f74d615 100644 --- a/lib/galaxy/webapps/galaxy/api/datatypes.py +++ b/lib/galaxy/webapps/galaxy/api/datatypes.py @@ -17,10 +17,13 @@ from galaxy.managers.datatypes import ( DatatypeDetails, DatatypesCombinedMap, DatatypesMap, + DatatypeEDAMDetailsDict, view_converters, view_index, view_mapping, view_sniffers, + view_edam_formats, + view_edam_data, ) from . import ( depends, @@ -43,6 +46,12 @@ UploadOnlyQueryParam: Optional[bool] = Query( description="Whether to return only datatypes which can be uploaded", ) +IdentifierOnly: Optional[bool] = Query( + default=True, + title="prefixIRI only", + description="Whether to return only the EDAM prefixIRI rather than the EDAM details", +) + @router.cbv class FastAPIDatatypes: @@ -111,15 +120,21 @@ class FastAPIDatatypes: summary="Returns a dictionary/map of datatypes and EDAM formats", response_description="Dictionary/map of datatypes and EDAM formats", ) - async def edam_formats(self) -> Dict[str, str]: + async def edam_formats( + self, + id_only: Optional[bool] = IdentifierOnly, + ) -> Union[DatatypeEDAMDetailsDict, Dict[str, str]]: """Gets a map of datatypes and their corresponding EDAM formats.""" - return self.datatypes_registry.edam_formats + return view_edam_formats(self.datatypes_registry, id_only) @router.get( "/api/datatypes/edam_data", summary="Returns a dictionary/map of datatypes and EDAM data", response_description="Dictionary/map of datatypes and EDAM data", ) - async def edam_data(self) -> Dict[str, str]: + async def edam_data( + self, + id_only: Optional[bool] = IdentifierOnly, + ) -> Union[DatatypeEDAMDetailsDict, Dict[str, str]]: """Gets a map of datatypes and their corresponding EDAM data.""" - return self.datatypes_registry.edam_data + return view_edam_data(self.datatypes_registry, id_only) From cb3c2942810512383e45e79c23bde215b7896ad8 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Tue, 16 Aug 2022 15:47:18 +0200 Subject: [PATCH 02/26] add tests for new apis --- lib/galaxy_test/api/test_datatypes.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/galaxy_test/api/test_datatypes.py b/lib/galaxy_test/api/test_datatypes.py index e3e4a21b250..84886e2bb0b 100644 --- a/lib/galaxy_test/api/test_datatypes.py +++ b/lib/galaxy_test/api/test_datatypes.py @@ -89,6 +89,15 @@ class DatatypesApiTestCase(ApiTestCase): edam_formats = response.json() assert isinstance(edam_formats, dict) assert edam_formats["ab1"] == "format_3000" + time.sleep(2) + + response = self._get("datatypes/edam_formats?id_only=false") + self._assert_status_code_is(response, 200) + edam_formats = response.json() + assert isinstance(edam_formats, dict) + assert isinstance(edam_formats["afg"], dict) + assert edam_formats["afg"]["prefix_IRI"] == "format_3582" + assert edam_formats["afg"]["label"] == "afg" def test_edam_data(self): response = self._get("datatypes/edam_data") @@ -96,6 +105,14 @@ class DatatypesApiTestCase(ApiTestCase): edam_data = response.json() assert isinstance(edam_data, dict) assert edam_data["ab1"] == "data_0924" + time.sleep(2) + + response = self._get("datatypes/edam_data?id_only=false") + edam_data = response.json() + assert isinstance(edam_data, dict) + assert isinstance(edam_data["afg"], dict) + assert edam_data["afg"]["prefix_IRI"] == "data_0925" + assert edam_data["afg"]["label"] == "Sequence assembly" def _index_datatypes(self, data=None): data = data or {} From da66f75a1e3c0592bc32243a109633cbed76a38d Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Tue, 16 Aug 2022 17:48:32 +0200 Subject: [PATCH 03/26] fix optional included_terms in load_edam_tree --- lib/galaxy/tool_util/edam_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/tool_util/edam_util.py b/lib/galaxy/tool_util/edam_util.py index da4d0560bbd..788cfa86c15 100644 --- a/lib/galaxy/tool_util/edam_util.py +++ b/lib/galaxy/tool_util/edam_util.py @@ -60,7 +60,7 @@ def load_edam_tree_from_tsv_stream(tsv_stream: TextIO, *included_terms: str): term_id = term[len(EDAM_PREFIX) :] # Only care about included terms - if (included_terms is not None) and not (term_id.startswith(included_terms)): + if included_terms and not (term_id.startswith(included_terms)): continue parents = fields[parents_column].split("|") From 712dd45328434ab35e6432e83112a0ff286a10a3 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 09:57:19 +0200 Subject: [PATCH 04/26] fix no config breaks registry --- lib/galaxy/datatypes/registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/datatypes/registry.py b/lib/galaxy/datatypes/registry.py index ba061710bee..06f48efed06 100644 --- a/lib/galaxy/datatypes/registry.py +++ b/lib/galaxy/datatypes/registry.py @@ -47,7 +47,7 @@ class ConfigurationError(Exception): class Registry: def __init__(self, config=None): - edam_ontology_path = config.edam_toolbox_ontology_path + edam_ontology_path = config.edam_toolbox_ontology_path if config is not None else None edam = load_edam_tree( None if not edam_ontology_path or not os.path.exists(edam_ontology_path) else edam_ontology_path, From 744b8128e0eae04399c2abefb9384a29a729cad3 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 10:15:59 +0200 Subject: [PATCH 05/26] fix edam_toolbox_ontology_path not in config causes crash --- lib/galaxy/datatypes/registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/datatypes/registry.py b/lib/galaxy/datatypes/registry.py index 06f48efed06..ae714731efb 100644 --- a/lib/galaxy/datatypes/registry.py +++ b/lib/galaxy/datatypes/registry.py @@ -47,7 +47,7 @@ class ConfigurationError(Exception): class Registry: def __init__(self, config=None): - edam_ontology_path = config.edam_toolbox_ontology_path if config is not None else None + edam_ontology_path = config.get("edam_toolbox_ontology_path", None) if config is not None else None edam = load_edam_tree( None if not edam_ontology_path or not os.path.exists(edam_ontology_path) else edam_ontology_path, From 85c6045248e796fc455a97523cf5bd329a752b99 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 10:29:39 +0200 Subject: [PATCH 06/26] explicitly reexport DatatypeEDAMDetailsDict --- lib/galaxy/managers/datatypes.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/managers/datatypes.py b/lib/galaxy/managers/datatypes.py index 95c46e19d36..9b8cc2559a1 100644 --- a/lib/galaxy/managers/datatypes.py +++ b/lib/galaxy/managers/datatypes.py @@ -104,14 +104,18 @@ def _get_edam_details(datatypes_registry: Registry, edam_ids: Dict[str, str]): return details_dict -def view_edam_formats(datatypes_registry: Registry, id_only: Optional[bool] = True) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: +def view_edam_formats( + datatypes_registry: Registry, id_only: Optional[bool] = True +) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: if id_only: return datatypes_registry.edam_formats else: return _get_edam_details(datatypes_registry, datatypes_registry.edam_formats) -def view_edam_data(datatypes_registry: Registry, id_only: Optional[bool] = True) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: +def view_edam_data( + datatypes_registry: Registry, id_only: Optional[bool] = True +) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: if id_only: return datatypes_registry.edam_data else: @@ -123,6 +127,7 @@ __all__ = ( "DatatypeDetails", "DatatypesCombinedMap", "DatatypesMap", + "DatatypeEDAMDetailsDict", "view_index", "view_mapping", "view_types_and_mapping", From 83e1db6404c2f67334edfd723e173aec6b2583e7 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 10:48:33 +0200 Subject: [PATCH 07/26] rename DatatypesEDAMDetailsDict sort imports --- lib/galaxy/datatypes/_schema.py | 2 +- lib/galaxy/managers/datatypes.py | 8 ++++---- lib/galaxy/webapps/galaxy/api/datatypes.py | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/galaxy/datatypes/_schema.py b/lib/galaxy/datatypes/_schema.py index d9b7ea5cfaf..6b618e77d0f 100644 --- a/lib/galaxy/datatypes/_schema.py +++ b/lib/galaxy/datatypes/_schema.py @@ -119,7 +119,7 @@ class DatatypeEDAMDetails(BaseModel): ) -class DatatypeEDAMDetailsDict(BaseModel): +class DatatypesEDAMDetailsDict(BaseModel): __root__: Dict[str, DatatypeEDAMDetails] = Field( title="Dict of EDAM details for formats", default={}, diff --git a/lib/galaxy/managers/datatypes.py b/lib/galaxy/managers/datatypes.py index 9b8cc2559a1..bb962439a62 100644 --- a/lib/galaxy/managers/datatypes.py +++ b/lib/galaxy/managers/datatypes.py @@ -11,8 +11,8 @@ from galaxy.datatypes._schema import ( DatatypeConverterList, DatatypeDetails, DatatypesCombinedMap, + DatatypesEDAMDetailsDict, DatatypesMap, - DatatypeEDAMDetailsDict, ) from galaxy.datatypes.data import Data from galaxy.datatypes.registry import Registry @@ -106,7 +106,7 @@ def _get_edam_details(datatypes_registry: Registry, edam_ids: Dict[str, str]): def view_edam_formats( datatypes_registry: Registry, id_only: Optional[bool] = True -) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: +) -> Union[Dict[str, str], DatatypesEDAMDetailsDict]: if id_only: return datatypes_registry.edam_formats else: @@ -115,7 +115,7 @@ def view_edam_formats( def view_edam_data( datatypes_registry: Registry, id_only: Optional[bool] = True -) -> Union[Dict[str, str], DatatypeEDAMDetailsDict]: +) -> Union[Dict[str, str], DatatypesEDAMDetailsDict]: if id_only: return datatypes_registry.edam_data else: @@ -126,8 +126,8 @@ __all__ = ( "DatatypeConverterList", "DatatypeDetails", "DatatypesCombinedMap", + "DatatypesEDAMDetailsDict", "DatatypesMap", - "DatatypeEDAMDetailsDict", "view_index", "view_mapping", "view_types_and_mapping", diff --git a/lib/galaxy/webapps/galaxy/api/datatypes.py b/lib/galaxy/webapps/galaxy/api/datatypes.py index 9e31f74d615..dec29010bd2 100644 --- a/lib/galaxy/webapps/galaxy/api/datatypes.py +++ b/lib/galaxy/webapps/galaxy/api/datatypes.py @@ -16,14 +16,14 @@ from galaxy.managers.datatypes import ( DatatypeConverterList, DatatypeDetails, DatatypesCombinedMap, + DatatypesEDAMDetailsDict, DatatypesMap, - DatatypeEDAMDetailsDict, view_converters, + view_edam_data, + view_edam_formats, view_index, view_mapping, view_sniffers, - view_edam_formats, - view_edam_data, ) from . import ( depends, @@ -123,7 +123,7 @@ class FastAPIDatatypes: async def edam_formats( self, id_only: Optional[bool] = IdentifierOnly, - ) -> Union[DatatypeEDAMDetailsDict, Dict[str, str]]: + ) -> Union[DatatypesEDAMDetailsDict, Dict[str, str]]: """Gets a map of datatypes and their corresponding EDAM formats.""" return view_edam_formats(self.datatypes_registry, id_only) @@ -135,6 +135,6 @@ class FastAPIDatatypes: async def edam_data( self, id_only: Optional[bool] = IdentifierOnly, - ) -> Union[DatatypeEDAMDetailsDict, Dict[str, str]]: + ) -> Union[DatatypesEDAMDetailsDict, Dict[str, str]]: """Gets a map of datatypes and their corresponding EDAM data.""" return view_edam_data(self.datatypes_registry, id_only) From 474b25c15b4884eec329963dc747794624f503ec Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 11:14:45 +0200 Subject: [PATCH 08/26] add new `datatypes` client route --- client/src/components/Datatypes.vue | 10 ++++++++++ client/src/entry/analysis/router.js | 5 +++++ lib/galaxy/webapps/galaxy/buildapp.py | 1 + 3 files changed, 16 insertions(+) create mode 100644 client/src/components/Datatypes.vue diff --git a/client/src/components/Datatypes.vue b/client/src/components/Datatypes.vue new file mode 100644 index 00000000000..ba2703cea5e --- /dev/null +++ b/client/src/components/Datatypes.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/client/src/entry/analysis/router.js b/client/src/entry/analysis/router.js index 483e67a1e87..509f49a3732 100644 --- a/client/src/entry/analysis/router.js +++ b/client/src/entry/analysis/router.js @@ -52,6 +52,7 @@ import { CloudAuth } from "components/User/CloudAuth"; import { ExternalIdentities } from "components/User/ExternalIdentities"; import { HistoryExport } from "components/HistoryExport/index"; import { StorageDashboardRouter } from "components/User/DiskUsage"; +import Datatypes from "components/Datatypes"; Vue.use(VueRouter); @@ -418,6 +419,10 @@ export function getRouter(Galaxy) { component: StoredWorkflowInvocations, props: true, }, + { + path: "datatypes", + component: Datatypes, + }, ], }, { path: "/login/start", component: Login }, diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index ec95f7f87fa..968815b1a2c 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -262,6 +262,7 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs): webapp.add_client_route("/interactivetool_entry_points/list") webapp.add_client_route("/libraries{path:.*?}") webapp.add_client_route("/storage{path:.*?}") + webapp.add_client_route("/datatypes") # ==== Done # Indicate that all configuration settings have been provided From fc1c06bf88821c10d09ec7308eba5e9c828ad359 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 11:57:48 +0200 Subject: [PATCH 09/26] resolve datatypes name conflict --- .../{Datatypes.vue => AvailableDatatypes.vue} | 8 ++++---- client/src/entry/analysis/router.js | 10 +++++----- lib/galaxy/webapps/galaxy/buildapp.py | 1 - 3 files changed, 9 insertions(+), 10 deletions(-) rename client/src/components/{Datatypes.vue => AvailableDatatypes.vue} (76%) diff --git a/client/src/components/Datatypes.vue b/client/src/components/AvailableDatatypes.vue similarity index 76% rename from client/src/components/Datatypes.vue rename to client/src/components/AvailableDatatypes.vue index ba2703cea5e..4b7184f0784 100644 --- a/client/src/components/Datatypes.vue +++ b/client/src/components/AvailableDatatypes.vue @@ -1,10 +1,10 @@ - - + + diff --git a/client/src/entry/analysis/router.js b/client/src/entry/analysis/router.js index 509f49a3732..e5be32725b1 100644 --- a/client/src/entry/analysis/router.js +++ b/client/src/entry/analysis/router.js @@ -22,6 +22,7 @@ import DatasetAttributes from "components/DatasetInformation/DatasetAttributes"; import DatasetDetails from "components/DatasetInformation/DatasetDetails"; import DatasetError from "components/DatasetInformation/DatasetError"; import DatasetList from "components/Dataset/DatasetList"; +import AvailableDatatypes from "components/AvailableDatatypes"; import DisplayStructured from "components/DisplayStructured"; import FormGeneric from "components/Form/FormGeneric"; import Grid from "components/Grid/Grid"; @@ -52,7 +53,6 @@ import { CloudAuth } from "components/User/CloudAuth"; import { ExternalIdentities } from "components/User/ExternalIdentities"; import { HistoryExport } from "components/HistoryExport/index"; import { StorageDashboardRouter } from "components/User/DiskUsage"; -import Datatypes from "components/Datatypes"; Vue.use(VueRouter); @@ -141,6 +141,10 @@ export function getRouter(Galaxy) { component: DatasetError, props: true, }, + { + path: "available_datatypes", + component: AvailableDatatypes, + }, { path: "histories/import", component: HistoryImport, @@ -419,10 +423,6 @@ export function getRouter(Galaxy) { component: StoredWorkflowInvocations, props: true, }, - { - path: "datatypes", - component: Datatypes, - }, ], }, { path: "/login/start", component: Login }, diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 968815b1a2c..ec95f7f87fa 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -262,7 +262,6 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs): webapp.add_client_route("/interactivetool_entry_points/list") webapp.add_client_route("/libraries{path:.*?}") webapp.add_client_route("/storage{path:.*?}") - webapp.add_client_route("/datatypes") # ==== Done # Indicate that all configuration settings have been provided From d78f0186818b8a4277773a93fe8c367b7f9e1db7 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 12:34:08 +0200 Subject: [PATCH 10/26] format python --- lib/galaxy/datatypes/registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/datatypes/registry.py b/lib/galaxy/datatypes/registry.py index ae714731efb..689c5642dec 100644 --- a/lib/galaxy/datatypes/registry.py +++ b/lib/galaxy/datatypes/registry.py @@ -19,9 +19,9 @@ from typing import ( import yaml import galaxy.util +from galaxy.tool_util.edam_util import load_edam_tree from galaxy.util import RW_R__R__ from galaxy.util.bunch import Bunch -from galaxy.tool_util.edam_util import load_edam_tree from . import ( binary, coverage, From c22011ed3e4da78556811d71e68d230eb546c79b Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:11:44 +0200 Subject: [PATCH 11/26] basic layout and filtering --- client/src/components/AvailableDatatypes.vue | 29 +++++++++--- client/src/composables/datatypes.js | 46 ++++++++++++++++++++ client/src/composables/filter.js | 28 ++++++++++++ client/src/entry/analysis/router.js | 2 +- lib/galaxy/webapps/galaxy/buildapp.py | 1 + 5 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 client/src/composables/datatypes.js create mode 100644 client/src/composables/filter.js diff --git a/client/src/components/AvailableDatatypes.vue b/client/src/components/AvailableDatatypes.vue index 4b7184f0784..9f1c0e8d037 100644 --- a/client/src/components/AvailableDatatypes.vue +++ b/client/src/components/AvailableDatatypes.vue @@ -1,10 +1,25 @@ - + - + + + diff --git a/client/src/composables/datatypes.js b/client/src/composables/datatypes.js new file mode 100644 index 00000000000..4d5baf56a91 --- /dev/null +++ b/client/src/composables/datatypes.js @@ -0,0 +1,46 @@ +import { ref } from "vue"; +import axios from "axios"; +import { getAppRoot } from "onload/loadConfig"; + +export function useGetDetailedDatatypes() { + const datatypesLoading = ref(true); + const datatypes = ref([]); + + async function getDatatypes() { + const datatypesPromise = axios.get(`${getAppRoot()}api/datatypes?extension_only=false`); + const datatypeEDAMFormatsPromise = axios.get(`${getAppRoot()}api/datatypes/edam_formats?id_only=false`); + const datatypeEDAMDataPromise = axios.get(`${getAppRoot()}api/datatypes/edam_data?id_only=false`); + + const [baseTypes, datatypeEDAMFormats, datatypeEDAMData] = await Promise.all([ + datatypesPromise, + datatypeEDAMFormatsPromise, + datatypeEDAMDataPromise, + ]); + + datatypes.value = baseTypes.data.map((type, i) => { + const typeEDAMFormat = datatypeEDAMFormats.data[type.extension] ?? null; + const typeEDAMData = datatypeEDAMData.data[type.extension] ?? null; + + return { + extension: type.extension, + description: type.description, + edamFormat: typeEDAMFormat.prefix_IRI, + edamFormatLabel: typeEDAMFormat.label, + edamFormatDefinition: typeEDAMFormat.definition, + edamData: typeEDAMData.prefix_IRI, + edamDataLabel: typeEDAMData.label, + edamDataDefinition: typeEDAMData.definition, + }; + }); + + datatypesLoading.value = false; + } + + try { + getDatatypes(); + } catch (e) { + console.error("unable to fetch available datatypes\n", e); + } + + return { datatypes, datatypesLoading }; +} diff --git a/client/src/composables/filter.js b/client/src/composables/filter.js new file mode 100644 index 00000000000..4af74f49e1b --- /dev/null +++ b/client/src/composables/filter.js @@ -0,0 +1,28 @@ +import { computed, unref } from "vue"; + +/** + * Filter array of objects, by comparing `filter` to all `fields` + */ +export function useFilterObjectArray(array, filter, objectFields) { + const filtered = computed(() => { + const f = unref(filter); + const arr = unref(array); + const fields = unref(objectFields); + + if (f === "") { + return arr; + } else { + return arr.filter((obj) => { + for (const field of fields) { + if (obj[field].toLowerCase().includes(f)) { + return true; + } + } + + return false; + }); + } + }); + + return filtered; +} diff --git a/client/src/entry/analysis/router.js b/client/src/entry/analysis/router.js index e5be32725b1..03714392483 100644 --- a/client/src/entry/analysis/router.js +++ b/client/src/entry/analysis/router.js @@ -142,7 +142,7 @@ export function getRouter(Galaxy) { props: true, }, { - path: "available_datatypes", + path: "datatypes", component: AvailableDatatypes, }, { diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index ec95f7f87fa..f1a689fe2c7 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -208,6 +208,7 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs): webapp.add_client_route("/admin/quotas") webapp.add_client_route("/admin/form/{form_id}") webapp.add_client_route("/admin/api_keys") + webapp.add_client_route("/datatypes") webapp.add_client_route("/login/start") webapp.add_client_route("/login/confirm") webapp.add_client_route("/tools/view") From 73cc49e6a7b89d182af3b68b13b5fa7d293698d2 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Wed, 17 Aug 2022 18:02:39 +0200 Subject: [PATCH 12/26] add table to render datatypes --- client/src/components/AvailableDatatypes.vue | 60 +++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/client/src/components/AvailableDatatypes.vue b/client/src/components/AvailableDatatypes.vue index 9f1c0e8d037..b867dfb3bf6 100644 --- a/client/src/components/AvailableDatatypes.vue +++ b/client/src/components/AvailableDatatypes.vue @@ -4,22 +4,66 @@ import { useGetDetailedDatatypes } from "composables/datatypes"; import { useFilterObjectArray } from "composables/filter"; import DelayedInput from "components/Common/DelayedInput"; -const fields = ["extension"]; - const filter = ref(""); +const filterFields = ["extension"]; const { datatypes } = useGetDetailedDatatypes(); -const filteredArray = useFilterObjectArray(datatypes, filter, fields); +const filteredDatatypes = useFilterObjectArray(datatypes, filter, filterFields); + +const fields = [ + { + key: "extension", + }, + { + key: "edamFormatLabel", + label: "EDAM Format", + }, + { + key: "edamDataLabel", + label: "EDAM Data", + }, +]; + +const edamLink = (edamIRI) => `https://edamontology.github.io/edam-browser/#${edamIRI}`; - + From 8296b27230ceb7692e1450b8e34942fbcd5eb4d5 Mon Sep 17 00:00:00 2001 From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com> Date: Thu, 18 Aug 2022 09:37:13 +0200 Subject: [PATCH 13/26] rename move and fix composables document composables --- client/src/components/AvailableDatatypes.vue | 6 +- client/src/composables/datatypes.js | 64 +++++++++++--------- client/src/composables/{ => utils}/filter.js | 8 ++- 3 files changed, 43 insertions(+), 35 deletions(-) rename client/src/composables/{ => utils}/filter.js (65%) diff --git a/client/src/components/AvailableDatatypes.vue b/client/src/components/AvailableDatatypes.vue index b867dfb3bf6..dc1ea0aed2b 100644 --- a/client/src/components/AvailableDatatypes.vue +++ b/client/src/components/AvailableDatatypes.vue @@ -1,13 +1,13 @@