Skip to content

Commit

Permalink
Merge pull request galaxyproject#17684 from ahmedhamidawan/grid_filte…
Browse files Browse the repository at this point in the history
…ring_bugs

[24.0] Grid filtering bug fixes
  • Loading branch information
mvdbeek authored Mar 19, 2024
2 parents 799fde4 + be59728 commit b9eed71
Show file tree
Hide file tree
Showing 12 changed files with 505 additions and 386 deletions.
22 changes: 1 addition & 21 deletions client/src/components/Common/FilterMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { faAngleDoubleUp, faQuestion, faRedo, faSearch } from "@fortawesome/free
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BButton, BModal } from "bootstrap-vue";
import { kebabCase } from "lodash";
import { computed, ref, watch } from "vue";
import { computed, ref } from "vue";
import type Filtering from "@/utils/filtering";
import { type Alias, getOperatorForAlias } from "@/utils/filtering";
Expand Down Expand Up @@ -68,7 +68,6 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<{
(e: "update:filter-text", filter: string): void;
(e: "on-backend-filter", filter: string): void;
(e: "update:show-advanced", showAdvanced: boolean): void;
(e: "on-search", filters: Record<string, string | boolean>, filterText?: string, backendFilter?: string): void;
}>();
Expand Down Expand Up @@ -127,25 +126,6 @@ function onToggle() {
function updateFilterText(newFilterText: string) {
emit("update:filter-text", newFilterText);
}
// as the filterText changes, emit a backend-filter that can be used as a backend query
watch(
() => props.filterText,
(newFilterText: string) => {
const defaultBackendFilter = props.filterClass.getFilterText(props.filterClass.defaultFilters, true);
const currentBackendFilter = props.filterClass.getFilterText(filters.value, true);
const backendFilter =
defaultBackendFilter === currentBackendFilter
? `${
defaultBackendFilter && !newFilterText.includes(defaultBackendFilter)
? defaultBackendFilter + " "
: ""
}` + newFilterText
: props.filterClass.getFilterText(filters.value, true);
emit("on-backend-filter", backendFilter);
}
);
</script>

<template>
Expand Down
270 changes: 161 additions & 109 deletions client/src/components/Grid/GridList.vue

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions client/src/components/History/CurrentHistory/HistoryPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,9 @@ async function onDrop() {
}
}
function updateFilterValue(newFilterText: string, newValue: any) {
function updateFilterValue(filterKey: string, newValue: any) {
const currentFilterText = filterText.value;
filterText.value = filterClass.setFilterValue(currentFilterText, newFilterText, newValue);
filterText.value = filterClass.setFilterValue(currentFilterText, filterKey, newValue);
}
function getItemKey(item: HistoryItem) {
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Panels/Menus/PanelViewMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<b-button
v-if="showAdvanced"
variant="link"
class="w-100"
class="w-100 text-decoration-none"
size="sm"
@click="$emit('update:show-advanced', !showAdvanced)">
<slot name="panel-view-selector"></slot><span class="sr-only">Close advanced tool search menu</span>
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/Workflow/WorkflowCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<{
(e: "tagClick", tag: string): void;
(e: "refreshList", overlayLoading?: boolean, b?: boolean): void;
(e: "update-filter", key: string, value: any): void;
}>();
const userStore = useUserStore();
Expand Down Expand Up @@ -124,7 +125,10 @@ async function onTagClick(tag: string) {
'workflow-shared': workflow.published,
}">
<div class="workflow-card-header">
<WorkflowIndicators :workflow="workflow" :published-view="publishedView" />
<WorkflowIndicators
:workflow="workflow"
:published-view="publishedView"
@update-filter="(k, v) => emit('update-filter', k, v)" />

<div class="workflow-count-actions">
<WorkflowInvocationsCount v-if="!isAnonymous && !shared" class="mx-1" :workflow="workflow" />
Expand Down
272 changes: 164 additions & 108 deletions client/src/components/Workflow/WorkflowFilters.js
Original file line number Diff line number Diff line change
@@ -1,115 +1,171 @@
import Filtering, { contains, equals, expandNameTag, toBool } from "utils/filtering";

export const helpHtml = `<div>
<p>This input can be used to filter the workflows displayed.</p>
export function helpHtml(activeList = "my") {
let extra = "";
if (activeList === "my") {
extra = `<dt><code>is:published</code></dt>
<dd>
Shows published workflows.
</dd>
<dt><code>is:importable</code></dt>
<dd>
Shows importable workflows (this also means they are URL generated).
</dd>
<dt><code>is:shared_with_me</code></dt>
<dd>
Shows workflows shared by another user directly with you.
</dd>
<dt><code>is:deleted</code></dt>
<dd>Shows deleted workflows.</dd>`;
} else if (activeList === "shared_with_me") {
extra = `<dt><code>user:____</code></dt>
<dd>
Shows workflows owned by the given user.
</dd>
<dt><code>is:published</code></dt>
<dd>
Shows published workflows.
</dd>`;
} else {
extra = `<dt><code>user:____</code></dt>
<dd>
Shows workflows owned by the given user.
</dd>
<dt><code>is:shared_with_me</code></dt>
<dd>
Shows workflows shared by another user directly with you.
</dd>`;
}

<p>
Text entered here will be searched against workflow names and workflow
tags. Additionally, advanced filtering tags can be used to refine the
search more precisely. Filtering tags are of the form
<code>&lt;tag_name&gt;:&lt;tag_value&gt;</code> or
<code>&lt;tag_name&gt;:'&lt;tag_value&gt;'</code>. For instance to
search just for RNAseq in the workflow name,
<code>name:rnsseq</code> can be used. Notice by default the search is
not case-sensitive. If the quoted version of tag is used, the search is
case sensitive and only full matches will be returned. So
<code>name:'RNAseq'</code> would show only workflows named exactly
<code>RNAseq</code>.
</p>
const conditionalHelpHtml = `<div>
<p>This menu can be used to filter the workflows displayed.</p>
<p>The available filtering tags are:</p>
<dl>
<dt><code>name</code></dt>
<dd>
Shows workflows with the given sequence of characters in their names.
</dd>
<dt><code>tag</code></dt>
<dd>
Shows workflows with the given workflow tag. You may also click
on a tag to filter on that tag directly.
</dd>
<dt><code>is:published</code></dt>
<dd>
Shows published workflows.
</dd>
<dt><code>is:importable</code></dt>
<dd>
Shows importable workflows (this also means they are URL generated).
</dd>
<dt><code>is:shared_with_me</code></dt>
<dd>
Shows workflows shared by another user directly with you.
</dd>
<dt><code>is:deleted</code></dt>
<dd>Shows deleted workflows.</dd>
</dl>
</div>`;
<p>
Text entered here will be searched against workflow names and workflow
tags. Additionally, advanced filtering tags can be used to refine the
search more precisely. Filtering tags are of the form
<code>&lt;tag_name&gt;:&lt;tag_value&gt;</code> or
<code>&lt;tag_name&gt;:'&lt;tag_value&gt;'</code>. For instance to
search just for RNAseq in the workflow name,
<code>name:rnsseq</code> can be used. Notice by default the search is
not case-sensitive. If the quoted version of tag is used, the search is
case sensitive and only full matches will be returned. So
<code>name:'RNAseq'</code> would show only workflows named exactly
<code>RNAseq</code>.
</p>
const validFilters = {
name: { placeholder: "name", type: String, handler: contains("name"), menuItem: true },
user: {
placeholder: "owner",
type: String,
handler: contains("user"),
menuItem: false,
},
tag: {
placeholder: "tag(s)",
type: "MultiTags",
handler: contains("tag", "tag", expandNameTag),
menuItem: true,
},
published: {
placeholder: "Filter on published workflows",
type: Boolean,
boolType: "is",
handler: equals("published", "published", toBool),
menuItem: true,
},
importable: {
placeholder: "Filter on importable workflows",
type: Boolean,
boolType: "is",
handler: equals("importable", "importable", toBool),
menuItem: true,
},
shared_with_me: {
placeholder: "Filter on workflows shared with me",
type: Boolean,
boolType: "is",
handler: equals("shared_with_me", "shared_with_me", toBool),
menuItem: true,
},
deleted: {
placeholder: "Filter on deleted workflows",
type: Boolean,
boolType: "is",
handler: equals("deleted", "deleted", toBool),
menuItem: true,
},
};
<p>The available filtering tags are:</p>
<dl>
<dt><code>name:____</code></dt>
<dd>
Shows workflows with the given sequence of characters in their names.
</dd>
<dt><code>tag:____</code></dt>
<dd>
Shows workflows with the given workflow tag. You may also click
on a tag to filter on that tag directly.
</dd>
${extra}
</dl>
</div>`;
return conditionalHelpHtml;
}

export const WorkflowFilters = new Filtering(validFilters, undefined, false, false);
export function WorkflowFilters(activeList = "my") {
const commonFilters = {
name: { placeholder: "name", type: String, handler: contains("name"), menuItem: true },
n: { handler: contains("n"), menuItem: false },
tag: {
placeholder: "tag(s)",
type: "MultiTags",
handler: contains("tag", "tag", expandNameTag),
menuItem: true,
},
t: { type: "MultiTags", handler: contains("t", "t", expandNameTag), menuItem: false },
};

const validPublishedFilters = {
...validFilters,
user: {
...validFilters.user,
menuItem: true,
},
published: {
...validFilters.published,
default: true,
menuItem: false,
},
shared_with_me: {
...validFilters.shared_with_me,
menuItem: false,
},
importable: {
...validFilters.importable,
menuItem: false,
},
};

export const PublishedWorkflowFilters = new Filtering(validPublishedFilters, undefined, false, false);
if (activeList === "my") {
return new Filtering(
{
...commonFilters,
published: {
placeholder: "Filter on published workflows",
type: Boolean,
boolType: "is",
handler: equals("published", "published", toBool),
menuItem: true,
},
importable: {
placeholder: "Filter on importable workflows",
type: Boolean,
boolType: "is",
handler: equals("importable", "importable", toBool),
menuItem: true,
},
shared_with_me: {
placeholder: "Filter on workflows shared with me",
type: Boolean,
boolType: "is",
handler: equals("shared_with_me", "shared_with_me", toBool),
menuItem: true,
},
deleted: {
placeholder: "Filter on deleted workflows",
type: Boolean,
boolType: "is",
handler: equals("deleted", "deleted", toBool),
menuItem: true,
},
},
undefined,
false,
false
);
} else if (activeList === "shared_with_me") {
return new Filtering(
{
...commonFilters,
user: {
placeholder: "owner",
type: String,
handler: contains("user"),
menuItem: true,
},
u: { handler: contains("u"), menuItem: false },
published: {
placeholder: "Filter on published workflows",
type: Boolean,
boolType: "is",
handler: equals("published", "published", toBool),
menuItem: true,
},
},
undefined,
false,
false
);
} else {
return new Filtering(
{
...commonFilters,
user: {
placeholder: "owner",
type: String,
handler: contains("user"),
menuItem: true,
},
u: { handler: contains("u"), menuItem: false },
shared_with_me: {
placeholder: "Filter on workflows shared with me",
type: Boolean,
boolType: "is",
handler: equals("shared_with_me", "shared_with_me", toBool),
menuItem: true,
},
},
undefined,
false,
false
);
}
}
Loading

0 comments on commit b9eed71

Please sign in to comment.