Skip to content

Commit

Permalink
Merge pull request #17847 from ahmedhamidawan/tool_panel_slow_computed
Browse files Browse the repository at this point in the history
  • Loading branch information
mvdbeek authored Mar 28, 2024
2 parents 7155ad7 + 4f0f753 commit 30bf8eb
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 28 deletions.
23 changes: 16 additions & 7 deletions client/src/components/Panels/Common/ToolSearch.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { BAlert } from "bootstrap-vue";
import { storeToRefs } from "pinia";
import { computed, type ComputedRef, onMounted, onUnmounted, type PropType, type Ref, ref, watch } from "vue";
import { computed, type ComputedRef, onMounted, onUnmounted, type PropType, watch } from "vue";
import { useRouter } from "vue-router/composables";
import { type Tool, type ToolSection, useToolStore } from "@/stores/toolStore";
Expand All @@ -12,6 +13,7 @@ import { type ToolSearchKeys } from "../utilities";
import DelayedInput from "@/components/Common/DelayedInput.vue";
import FilterMenu from "@/components/Common/FilterMenu.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
const router = useRouter();
Expand Down Expand Up @@ -67,8 +69,6 @@ const emit = defineEmits<{
(e: "onQuery", query: string): void;
}>();
const searchWorker: Ref<Worker | undefined> = ref(undefined);
const localFilterText = computed({
get: () => {
return props.query !== null ? props.query : "";
Expand Down Expand Up @@ -112,15 +112,18 @@ const ToolFilters: ComputedRef<Filtering<string>> = computed(() => new Filtering
const { currentFavorites } = storeToRefs(useUserStore());
const toolStore = useToolStore();
const { searchWorker } = storeToRefs(toolStore);
const sectionNames = toolStore.sectionDatalist("default").map((option: { value: string; text: string }) => option.text);
const ontologyList = toolStore
.sectionDatalist("ontology:edam_topics")
.concat(toolStore.sectionDatalist("ontology:edam_operations"));
onMounted(() => {
searchWorker.value = new Worker(new URL("../toolSearch.worker.js", import.meta.url));
// initialize worker
if (!searchWorker.value) {
searchWorker.value = new Worker(new URL("components/Panels/toolSearch.worker.js", import.meta.url));
}
searchWorker.value.onmessage = ({ data }) => {
const { type, payload, sectioned, query, closestTerm } = data;
if (type === "searchToolsByKeysResult" && query === props.query) {
Expand All @@ -134,7 +137,10 @@ onMounted(() => {
});
onUnmounted(() => {
searchWorker.value?.terminate();
// The worker is not terminated but it will not be listening to messages
if (searchWorker.value?.onmessage) {
searchWorker.value.onmessage = null;
}
});
watch(
Expand Down Expand Up @@ -178,7 +184,7 @@ function onAdvancedSearch(filters: any) {
</script>

<template>
<div>
<div v-if="searchWorker">
<FilterMenu
v-if="props.enableAdvanced"
:class="!propShowAdvanced && 'mb-3'"
Expand Down Expand Up @@ -245,4 +251,7 @@ function onAdvancedSearch(filters: any) {
:placeholder="placeholder"
@change="checkQuery" />
</div>
<BAlert v-else class="mb-3" variant="info" show>
<LoadingSpan message="Loading Tool Search" />
</BAlert>
</template>
8 changes: 3 additions & 5 deletions client/src/components/Panels/ToolBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,6 @@ const localPanel: ComputedRef<Record<string, Tool | ToolSectionType> | null> = c
}
});
const sectionIds = computed(() => Object.keys(localPanel.value || {}));
const favWorkflows = computed(() => {
const Galaxy = getGalaxyInstance();
const storedWorkflowMenuEntries = Galaxy && Galaxy.config.stored_workflow_menu_entries;
Expand Down Expand Up @@ -298,10 +296,10 @@ function setButtonText() {
:query-filter="queryFilter || undefined"
:disable-filter="true"
@onClick="onToolClick" />
<div v-for="(sectionId, key) in sectionIds" :key="key">
<div v-for="(panel, key) in localPanel" :key="key">
<ToolSection
v-if="localPanel[sectionId]"
:category="localPanel[sectionId] || {}"
v-if="panel"
:category="panel || {}"
:query-filter="queryFilter || undefined"
@onClick="onToolClick" />
</div>
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/Panels/ToolPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const emit = defineEmits<{
const arePanelsFetched = ref(false);
const toolStore = useToolStore();
const { currentPanelView, defaultPanelView, isPanelPopulated, loading, panel, panelViews } = storeToRefs(toolStore);
const { currentPanelView, defaultPanelView, isPanelPopulated, loading, panel, panelViews, currentPanel } =
storeToRefs(toolStore);
const loadingView = ref<string | undefined>(undefined);
const query = ref("");
Expand Down Expand Up @@ -192,6 +193,9 @@ function onInsertWorkflowSteps(workflowId: string, workflowStepCount: number | u
</b-badge>
</div>
</div>
<b-alert v-else-if="currentPanel" class="m-2" variant="info" show>
<LoadingSpan message="Loading Toolbox" />
</b-alert>
</template>

<style lang="scss" scoped>
Expand Down
36 changes: 23 additions & 13 deletions client/src/components/Panels/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,29 +158,39 @@ export function getValidToolsInCurrentView(
isWorkflowPanel = false,
excludedSectionIds: string[] = []
) {
const toolEntries = Object.entries(toolsById).filter(([, tool]) => {
// filter on non-hidden, non-disabled, and workflow compatibile (based on props.workflow)
return (
!tool.hidden &&
tool.disabled !== true &&
!(isWorkflowPanel && !tool.is_workflow_compatible) &&
!excludedSectionIds.includes(tool.panel_section_id)
);
});
return Object.fromEntries(toolEntries);
const excludeSet = new Set(excludedSectionIds);
const validTools: Record<string, Tool> = {};

for (const [toolId, tool] of Object.entries(toolsById)) {
const { panel_section_id, hidden, disabled, is_workflow_compatible } = tool;
if (
!excludeSet.has(panel_section_id) &&
!hidden &&
disabled !== true &&
!(isWorkflowPanel && !is_workflow_compatible)
) {
validTools[toolId] = tool;
}
}

return validTools;
}

/** Looks in each section of `currentPanel` and filters `section.tools` on `validToolIdsInCurrentView` */
export function getValidToolsInEachSection(
validToolIdsInCurrentView: string[],
currentPanel: Record<string, Tool | ToolSection>
) {
// use a set for fast membership lookup
const idSet = new Set(validToolIdsInCurrentView);
return Object.entries(currentPanel).map(([id, section]) => {
const validatedSection = { ...section } as ToolSection;
if (validatedSection.tools && Array.isArray(validatedSection.tools)) {
// assign sectionTools to avoid repeated getter access
const sectionTools = validatedSection.tools;
if (sectionTools && Array.isArray(sectionTools)) {
// filter on valid tools and panel labels in this section
validatedSection.tools = validatedSection.tools.filter((toolId) => {
if (typeof toolId === "string" && validToolIdsInCurrentView.includes(toolId)) {
validatedSection.tools = sectionTools.filter((toolId) => {
if (typeof toolId === "string" && idSet.has(toolId)) {
return true;
} else if (typeof toolId !== "string") {
// is a special case where there is a label within a section
Expand Down
7 changes: 5 additions & 2 deletions client/src/stores/toolStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import axios from "axios";
import { defineStore } from "pinia";
import Vue, { computed, Ref, ref } from "vue";
import Vue, { computed, Ref, ref, shallowRef } from "vue";

import { createWhooshQuery, filterTools, types_to_icons } from "@/components/Panels/utilities";
import { useUserLocalStorage } from "@/composables/userLocalStorage";
Expand Down Expand Up @@ -75,12 +75,14 @@ export interface PanelView {
export const useToolStore = defineStore("toolStore", () => {
const currentPanelView: Ref<string> = useUserLocalStorage("tool-store-view", "");
const defaultPanelView: Ref<string> = ref("");
const toolsById = ref<Record<string, Tool>>({});
const toolsById = shallowRef<Record<string, Tool>>({});
const toolResults = ref<Record<string, string[]>>({});
const panel = ref<Record<string, Record<string, Tool | ToolSection>>>({});
const panelViews = ref<Record<string, PanelView>>({});
const loading = ref(false);

const searchWorker = ref<Worker | undefined>(undefined);

const getToolForId = computed(() => {
return (toolId: string) => toolsById.value[toolId];
});
Expand Down Expand Up @@ -278,6 +280,7 @@ export const useToolStore = defineStore("toolStore", () => {
currentPanel,
isPanelPopulated,
sectionDatalist,
searchWorker,
fetchToolForId,
fetchTools,
fetchPanelViews,
Expand Down

0 comments on commit 30bf8eb

Please sign in to comment.