Merge pull request #12448 from jmchilton/tool_panel_views_0

Easier to use static tool panel views.
This commit is contained in:
Marius van den Beek
2021-09-16 10:41:23 +02:00
committed by GitHub
5 changed files with 98 additions and 13 deletions
@@ -1,5 +1,5 @@
from enum import Enum
from typing import List, Optional, Union
from typing import Any, cast, List, Optional, Union
from pydantic import BaseModel, Field
from typing_extensions import Literal
@@ -33,7 +33,7 @@ OptionalExclusionList = Optional[List[Exclusions]]
class Tool(BaseModel):
content_type: Literal['tool'] = Field(alias="type")
content_type: Literal['tool'] = Field("tool", alias="type")
id: str
class Config:
@@ -78,13 +78,18 @@ SectionContent = Union[
class HasItems:
items: Optional[List[Any]]
@property
def items_expanded(self):
def items_expanded(self) -> Optional[List['ExpandedRootContent']]:
if self.items is None:
return None
# replace SectionAliases with individual SectionAlias objects
# replace LabelShortcuts with Labels
items = []
items: List[ExpandedRootContent] = []
for item in self.items:
item = cast(RootContent, item)
if isinstance(item, SectionAliases):
for section in item.sections:
section_alias = SectionAlias(
@@ -138,14 +143,23 @@ RootContent = Union[
ItemsFrom,
]
ExpandedRootContent = Union[
Section,
SectionAlias,
Tool,
Label,
Workflow,
ItemsFrom,
]
class StaticToolBoxView(BaseModel, HasItems):
id: str
name: str
description: Optional[str]
view_type: StaticToolBoxViewTypeEnum = Field(alias="type")
items: List[RootContent]
excludes: Optional[List[Exclusions]]
items: Optional[List[RootContent]] # if empty, use integrated tool panel
excludes: OptionalExclusionList
@staticmethod
def from_dict(as_dict):
+51 -7
View File
@@ -1,12 +1,17 @@
import logging
import re
from typing import Optional
from .definitions import (
ExcludeTool,
ExcludeToolRegex,
ExcludeTypes,
ExpandedRootContent,
Label,
Section,
SectionAlias,
StaticToolBoxView,
Tool,
Workflow,
)
from .interface import (
@@ -16,6 +21,7 @@ from .interface import (
ToolPanelViewModelType,
)
from ..panel import (
panel_item_types,
ToolPanelElements,
ToolSection,
ToolSectionLabel,
@@ -65,12 +71,15 @@ class StaticToolPanelView(ToolPanelView):
def apply_view(self, base_tool_panel: ToolPanelElements, toolbox_registry: ToolBoxRegistry) -> ToolPanelElements:
def apply_filter(definition, elems):
if definition.excludes:
elems.apply_filter(build_filter(definition.excludes))
excludes = self._all_excludes(definition)
if excludes:
elems.apply_filter(build_filter(excludes))
def definition_with_items_to_panel(definition, allow_sections: bool = True):
def definition_with_items_to_panel(definition, allow_sections: bool = True, items=None):
new_panel = ToolPanelElements()
for element in definition.items_expanded:
if items is None:
items = definition.items_expanded
for element in items:
if element.content_type == "section":
assert allow_sections
section_def: Section = element
@@ -145,12 +154,47 @@ class StaticToolPanelView(ToolPanelView):
else:
raise AssertionError("Unknown static toolbox configuration element encountered.")
if definition.excludes:
new_panel.apply_filter(build_filter(definition.excludes))
excludes = self._all_excludes(definition)
if excludes:
new_panel.apply_filter(build_filter(excludes))
return new_panel
return definition_with_items_to_panel(self._definition)
root_defintion = self._definition
root_items = root_defintion.items_expanded
if root_items is None:
root_items = []
# No items found, use base tool panel and apply filters to that...
for (_, panel_type, panel_value) in base_tool_panel.panel_items_iter():
item: Optional[ExpandedRootContent] = None
if panel_type == panel_item_types.TOOL:
item = Tool(
id=panel_value.id,
)
elif panel_type == panel_item_types.SECTION:
item = SectionAlias(
section=panel_value.id,
)
elif panel_type == panel_item_types.LABEL:
item = Label(
id=panel_value.id,
text=panel_value.text,
)
elif panel_type == panel_item_types.WORKFLOW:
item = Workflow(
id=panel_value.id,
)
if item is None:
raise Exception("Unknown panel item type encountered.")
root_items.append(item)
return definition_with_items_to_panel(root_defintion, items=root_items)
def _all_excludes(self, has_excludes):
excludes = has_excludes.excludes or []
if has_excludes != self._definition and self._definition.excludes:
excludes.extend(self._definition.excludes)
return excludes
def to_model(self) -> ToolPanelViewModel:
model_id = self._definition.id
@@ -0,0 +1,7 @@
name: Globally Applied Filters
type: activity
items:
- section: test
excludes:
- tool_id_regex: 'multi_data_.*'
- tool_id_regex: '.*_text_option'
@@ -0,0 +1,5 @@
name: Globally Applied Filters
type: activity
excludes:
- tool_id_regex: 'multi_data_.*'
- tool_id_regex: '.*_text_option'
+15
View File
@@ -95,6 +95,21 @@ class PanelViewsFromDirectoryIntegrationTestCase(integration_util.IntegrationTes
assert len(index_as_list) == 2
assert model_classes(index_as_list) == ["ToolSection", "ToolSection"]
def test_global_filters(self):
index = self.galaxy_interactor.get("tools", data=dict(in_panel=True, view="custom_11"))
verify_custom_regex_filtered(index)
def test_global_filters_on_integrated_panel(self):
index = self.galaxy_interactor.get("tools", data=dict(in_panel=True, view="custom_12"))
index.raise_for_status()
index_as_list = index.json()
sections = [x for x in index_as_list if x["model_class"] == "ToolSection"]
assert len(sections) == 2
section = sections[0]
assert section["id"] == "test"
tools = section["elems"]
assert len(tools) == 2, len(tools)
class PanelViewsFromConfigIntegrationTestCase(integration_util.IntegrationTestCase):