Skip to content

Commit

Permalink
add ToolSection.panel_labels to api return, to include any sub
Browse files Browse the repository at this point in the history
sections within a ToolSection
  • Loading branch information
ahmedhamidawan committed Sep 27, 2023
1 parent bf35e90 commit f49b7f2
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 14 deletions.
12 changes: 10 additions & 2 deletions client/src/components/Panels/Common/ToolSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { eventHub } from "@/components/plugins/eventHub.js";
import { useConfig } from "@/composables/config";
import { type Tool as ToolType } from "@/stores/toolStore";
import { type Tool as ToolType, type ToolSectionLabel as LabelType } from "@/stores/toolStore";
import { useToolStore } from "@/stores/toolStore";
import { type Workflow } from "@/stores/workflowStore";
import ariaAlert from "@/utils/ariaAlert";
Expand Down Expand Up @@ -66,7 +66,15 @@ const elems = computed(() => {
return props.category.elems;
}
if (props.category.tools !== undefined && props.category.tools.length > 0) {
return props.category.tools.map((toolId: string) => toolStore.getToolForId(toolId));
return props.category.tools.map((toolId: string) => {
const tool = toolStore.getToolForId(toolId);
if (!tool && toolId.startsWith("panel_label_") && props.category.panel_labels) {
const labelId = toolId.split("panel_label_")[1];
return props.category.panel_labels.find((label: LabelType) => label.id === labelId);
} else {
return tool;
}
});
}
return [];
});
Expand Down
30 changes: 24 additions & 6 deletions client/src/components/Panels/ToolBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useRouter } from "vue-router/composables";
import { getGalaxyInstance } from "@/app";
import { useGlobalUploadModal } from "@/composables/globalUploadModal";
import { getAppRoot } from "@/onload/loadConfig";
import { type Tool, type ToolSection as ToolSectionType } from "@/stores/toolStore";
import { type Tool, type ToolSection as ToolSectionType, type ToolSectionLabel } from "@/stores/toolStore";
import { useToolStore } from "@/stores/toolStore";
import { Workflow, type Workflow as WorkflowType } from "@/stores/workflowStore";
import localize from "@/utils/localization";
Expand Down Expand Up @@ -92,14 +92,24 @@ const dataManagerSection = computed(() => {
/** `toolsById` from `toolStore`, except it only has valid tools for `props.workflow` value */
const localToolsById = computed(() => {
// Filter the items with is_compat === true
const addedToolTexts: string[] = [];
if (toolStore.toolsById && Object.keys(toolStore.toolsById).length > 0) {
const toolEntries = Object.entries(toolStore.toolsById).filter(
([_, tool]: [string, any]) =>
const toolEntries = Object.entries(toolStore.toolsById).filter(([_, tool]: [string, any]) => {
// filter out duplicate tools (different ids, same exact name+description)
// related ticket: https://github.com/galaxyproject/galaxy/issues/16145
const toolText: string = tool.name + tool.description;
if (addedToolTexts.includes(toolText)) {
return false;
} else {
addedToolTexts.push(toolText);
}
// filter on non-hidden, non-disabled, and workflow compatibile (based on props.workflow)
return (
!tool.hidden &&
tool.disabled !== true &&
(props.workflow ? tool.is_workflow_compatible : !SECTION_IDS_TO_EXCLUDE.includes(tool.panel_section_id))
);
);
});
return Object.fromEntries(toolEntries);
}
return {};
Expand All @@ -111,7 +121,15 @@ const localSectionsById = computed(() => {
// for all values that are `ToolSection`s, filter out tools that aren't in `localToolsById`
const sectionEntries = Object.entries(currentPanel.value).map(([id, section]: [string, any]) => {
if (section.tools && Array.isArray(section.tools)) {
section.tools = section.tools.filter((tool: string) => validToolIdsInCurrentView.includes(tool));
section.tools = section.tools.filter((toolId: string) => {
if (validToolIdsInCurrentView.includes(toolId)) {
return true;
} else if (toolId.startsWith("panel_label_") && section.panel_labels) {
// panel_label_ is a special case where there is a label within a section
const labelId = toolId.split("panel_label_")[1];
return section.panel_labels.find((label: ToolSectionLabel) => label.id === labelId) !== undefined;
}
});
}
return [id, section];
});
Expand Down
15 changes: 13 additions & 2 deletions client/src/stores/toolStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,18 @@ export interface ToolSection {
version?: string;
description?: string;
links?: Record<string, string>;
tools: string[];
tools?: string[];
elems?: ToolSection[];
panel_labels?: string[];
}

export interface ToolSectionLabel {
model_class: string;
id: string;
text: string;
version?: string;
description?: string | null;
links?: Record<string, string> | null;
}

// TODO: Use this in ToolSearch.vue
Expand Down Expand Up @@ -147,8 +158,8 @@ export const useToolStore = defineStore("toolStore", () => {
await axios
.get(`${getAppRoot()}api/tools?in_panel=False`)
.then(({ data }) => {
loading.value = false;
saveAllTools(data.tools);
loading.value = false;
})
.catch((error) => {
console.error(error);
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/tool_util/toolbox/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,7 @@ def to_panel_view(self, trans, in_panel=True, tool_help=False, view=None, **kwds
view = self._default_panel_view
view_contents = {}
rval[view] = view_contents
panel_elts = list(self.tool_panel_contents(trans, view=view, **kwds))
panel_elts = self.tool_panel_contents(trans, view=view, **kwds)
for elt in panel_elts:
# Only use cache for objects that are Tools.
if hasattr(elt, "tool_type"):
Expand Down
22 changes: 19 additions & 3 deletions lib/galaxy/tool_util/toolbox/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,37 @@ def copy(self):
return copy

def to_dict(self, trans, link_details=False, tool_help=False, toolbox=None, only_ids=False):
"""Return a dict that includes section's attributes."""
"""Return a dict that includes section's attributes.
if `only_ids` is `True`, we store only the ids of the section's tools in `section.tools`
(and full `ToolSectionLabel` objects in `section.panel_labels` if any are present)
if `only_ids` is `False`, we store the section's full `Tool` (and any other) objects in
`section.elems`
"""

section_dict = super().to_dict()
section_elts = []
section_panel_labels = []
kwargs = dict(trans=trans, link_details=link_details, tool_help=tool_help)
for elt in self.elems.values():
if hasattr(elt, "tool_type") and toolbox:
if only_ids:
section_elts.append(elt.id)
else:
section_elts.append(toolbox.get_tool_to_dict(trans, elt, tool_help=tool_help))
elif only_ids is False:
section_elts.append(elt.to_dict(**kwargs))
else:
# if section has a ToolSectionLabel within it
if only_ids and elt.text:
section_panel_labels.append(elt.to_dict(**kwargs))
section_elts.append("panel_label_" + str(elt.id))
else:
section_elts.append(elt.to_dict(**kwargs))

if only_ids:
section_dict["tools"] = section_elts
if section_panel_labels:
section_dict["panel_labels"] = section_panel_labels
else:
section_dict["elems"] = section_elts

Expand All @@ -98,6 +113,7 @@ def to_dict(self, trans, link_details=False, tool_help=False, toolbox=None, only
def panel_items(self):
return self.elems


class ToolSectionLabel(Dictifiable):
"""
A label for a set of tools that can be displayed above groups of tools
Expand Down

0 comments on commit f49b7f2

Please sign in to comment.