From 72408b3e939f33ca6bf200a8e3b26fa06dc7a2ff Mon Sep 17 00:00:00 2001 From: Remi PLANEL <rplanel@pasteur.fr> Date: Fri, 5 Jan 2024 09:38:03 +0100 Subject: [PATCH] refresh filter on btn click --- components/AutocompleteMeiliFacets.vue | 81 +++++++++++++++----------- components/ServerDbTable.vue | 28 ++++----- components/content/RefseqDb.vue | 23 ++++---- 3 files changed, 75 insertions(+), 57 deletions(-) diff --git a/components/AutocompleteMeiliFacets.vue b/components/AutocompleteMeiliFacets.vue index f29026ef..2133accd 100644 --- a/components/AutocompleteMeiliFacets.vue +++ b/components/AutocompleteMeiliFacets.vue @@ -8,33 +8,33 @@ export interface FilterItem { props: Record<string, any> } +export interface FacetItem { + title: string + value: string +} + +export interface FacetCategory { + title: string + icon: string +} + +export type FacetInputItem = FacetItem | FacetCategory + export interface Props { db: string modelValue: string | undefined + facets: MaybeRef<FacetInputItem[]> } const emit = defineEmits(['update:modelValue']) -// const emit = defineEmits(["refresh:search"]) -const msfilter = defineModel<string>("msfilter", { default: "" }) const props = withDefaults(defineProps<Props>(), { modelValue: "" }); const filterItems = ref<FilterItem[] | undefined>(undefined) const { result: msResult } = useMeiliSearch(props.db) - - - - -const reactiveParams = reactive({ - facets: ["*"], - filter: [], - sort: ["type:asc"], -}) - - const isAutocompleteFocused = ref<boolean>(false) -const facets = computed(() => { +const computedFacets = computed(() => { const toValMsResult = toValue(msResult) if (toValMsResult?.facetDistribution) { return Object.keys(toValMsResult?.facetDistribution) @@ -42,6 +42,17 @@ const facets = computed(() => { else { return undefined } }) +const allFacets = ref(undefined) +onMounted(() => { + + // get the facets and keep it + const toValMsResult = toValue(msResult) + if (toValMsResult?.facetDistribution) { + allFacets.value = { ...toValMsResult?.facetDistribution } + } +}) + + const filterStep = computed(() => { const toValFilterItems = toValue(filterItems) if (toValFilterItems !== undefined) { @@ -76,13 +87,12 @@ const outerOperatorItems = ref<FilterItem[]>([ }, ]) -const autocompleteItems = computed(() => { +const autocompleteItems = computed(() => { const toValFilterItems = toValue(filterItems) - const index = toValFilterItems?.length ?? 0 if (filterStep.value === undefined || filterStep.value === 0) { - return toValue(facets)?.map(value => { + return toValue(computedFacets)?.map(value => { return { type: "facet", value: `${value}-${index}`, @@ -104,7 +114,8 @@ const autocompleteItems = computed(() => { const { type, value } = toValFilterItems?.slice(-2, -1)[0] const sanitizedValue = value.split("-")[0] // console.log("compute new facets") - const facetDistri = msResult.value?.facetDistribution + // const facetDistri = msResult.value?.facetDistribution + const facetDistri = allFacets.value // console.log(facetDistri) return facetDistri?.[sanitizedValue] ? Object.entries(facetDistri[sanitizedValue]).map(([key, val]) => { return { @@ -137,7 +148,8 @@ const isValidFilters = computed(() => { else { const toValLastFilterItem = toValue(lastFilterItem) if (toValLastFilterItem !== undefined) { - return toValLastFilterItem.type === 'value' && isAutocompleteFocused.value === false + return toValLastFilterItem.type === 'value' + // && isAutocompleteFocused.value === false // || (toValFilterStep === 0 && toValLastFilterItem.type === "outerOperator" && toValLastFilterItem.value.split("-")[0] === "AND") } } @@ -169,33 +181,34 @@ function updateAutocompleteFocused(isFocused: boolean) { isAutocompleteFocused.value = isFocused } -watchEffect(() => { - console.log("watch effect") - - const toValFilterStep = toValue(filterStep) - const toValLastFilterItem = toValue(lastFilterItem) - console.log(toValFilterStep) - console.log(toValLastFilterItem?.type) - console.log(toValLastFilterItem?.value) - +function emitUpdateModelValue() { if (toValue(isValidFilters)) { - console.log("should refresh the search in compo") const meiliFilter = toMeiliFilter(toValue(filterItems)) - console.log(meiliFilter) emit('update:modelValue', meiliFilter) } +} + +function clearFilters() { + filterItems.value = undefined + emitUpdateModelValue() +} -}) </script> <template> <v-autocomplete v-model:model-value="filterItems" :items="autocompleteItems" auto-select-first chips clearable multiple - return-object label="Filter results..." prepend-inner-icon="md:search" single-line item-value="value" - item-title="title" class="mx-2" @update:focused="updateAutocompleteFocused"> + return-object label="Filter results..." prepend-inner-icon="md:filter_alt" hide-details="auto" single-line + item-value="value" item-title="title" class="mx-2" @click:clear="clearFilters" + @update:focused="updateAutocompleteFocused"> <template #item="{ props, item }"> <v-list-item v-bind="{ ...props, active: false }" :title="item.title" :subtitle="item.raw?.count ? item.raw.count : ''" :value="props.value"> </v-list-item> - </template></v-autocomplete> + </template> + <template #append> + <v-btn variant="text" icon="md:filter_alt" @click="emitUpdateModelValue" :disabled="!isValidFilters"></v-btn> + </template> + + </v-autocomplete> </template> \ No newline at end of file diff --git a/components/ServerDbTable.vue b/components/ServerDbTable.vue index 765978e8..4135b068 100644 --- a/components/ServerDbTable.vue +++ b/components/ServerDbTable.vue @@ -4,7 +4,7 @@ import { useCsvDownload } from "@/composables/useCsvDownload" import { useSlots } from 'vue' import { useDisplay } from "vuetify"; import { useThrottleFn } from '@vueuse/core' - +import type { FacetInputItem } from '@/components/AutocompleteMeiliFacets.vue' import { useMeiliSearch } from "#imports" // import { saveAs } from "file-saver"; import { useFileSystemAccess } from '@vueuse/core' @@ -26,7 +26,7 @@ export interface Props { title?: string db?: string sortBy?: SortItem[] - facets: MaybeRef<string[]> + facets: MaybeRef<FacetInputItem[]> numericalFilters?: MaybeRef<string | undefined> dataTableServerProps: Record<string, any> columnsToDownload?: MaybeRef<string[] | undefined> @@ -168,6 +168,9 @@ const throttleSearch = useThrottleFn(async () => { searchOrFilter() emitRefreshRes() }, 300) + + + async function searchOrFilter() { // do something, it will be called at most 1 time per second @@ -187,12 +190,11 @@ async function searchOrFilter() { } function emitRefreshRes() { - console.log("emit refresh:search") const q = search.value emit("refresh:search", { index: props.db, query: q, - params: { ...notPaginatedParams.value, filter: toValue(computedFilter), sort: msSortBy.value } + params: { ...notPaginatedParams.value, filter: toValue(msFilterCompo), sort: msSortBy.value } }) } @@ -375,8 +377,8 @@ function focusedOrBlur(isFocused: boolean) { </v-autocomplete> </v-toolbar> <v-toolbar> - <AutocompleteMeiliFacets v-model="msFilterCompo" :db="props.db" - @refresh:search="() => console.log('refresh the search new compo')"> + <AutocompleteMeiliFacets v-model="msFilterCompo" :db="props.db" :facets="$props.facets" + @update:modelValue="emitRefreshRes"> </AutocompleteMeiliFacets> </v-toolbar> </template> @@ -395,8 +397,8 @@ function focusedOrBlur(isFocused: boolean) { :disabled="pendingDownloadData" prepend-inner-icon="mdi-magnify" single-line clearable @update:focused="focusedOrBlur"></v-text-field> </v-card> - <v-card variant="flat" color="transparent" :min-width="500" class="mx-2" :rounded="false"> - <!-- <v-autocomplete ref="autocompleteInput" hide-details v-model:model-value="filterOrSearch" + <!--<v-card variant="flat" color="transparent" :min-width="500" class="mx-2" :rounded="false"> + <v-autocomplete ref="autocompleteInput" hide-details v-model:model-value="filterOrSearch" auto-select-first chips clearable label="Filter results..." :items="autocompleteItems" single-line item-value="value" item-title="title" multiple return-object :disabled="pendingDownloadData" prepend-inner-icon="md:search" @@ -413,12 +415,12 @@ function focusedOrBlur(isFocused: boolean) { </v-list-item> </template> - </v-autocomplete> --> + </v-autocomplete> - </v-card> - <v-card> - <AutocompleteMeiliFacets v-model="msFilterCompo" :db="props.db" - @refresh:search="() => console.log('refresh the search new compo')"> + </v-card>--> + <v-card variant="flat" color="transparent" :min-width="500" class="mx-2" :rounded="false"> + <AutocompleteMeiliFacets v-model="msFilterCompo" :db="props.db" :facets="props.facets" + @update:modelValue="emitRefreshRes"> </AutocompleteMeiliFacets> </v-card> diff --git a/components/content/RefseqDb.vue b/components/content/RefseqDb.vue index dc75fe82..4dea5562 100644 --- a/components/content/RefseqDb.vue +++ b/components/content/RefseqDb.vue @@ -10,6 +10,7 @@ import { useDownloadBlob } from '@/composables/useDownloadBlob'; import type { ComponentPublicInstance } from 'vue' +import type { FacetInputItem } from '@/components/AutocompleteMeiliFacets.vue' const sortBy: Ref<SortItem[]> = ref([{ key: 'type', order: "asc" }]) const itemValue = ref("id"); @@ -21,16 +22,18 @@ const { serialize } = useSerialize() const { rasterize } = useRasterize() const { download } = useDownloadBlob() -const facets = ref([ - "replicon", - "type", - "subtype", - "Superkingdom", - "phylum", - "order", - "family", - "genus", - "species", +const facets = ref<FacetInputItem[]>([ + { title: "Replicon", value: "replicon", icon: "" }, + { title: "Defense System", icon: "" }, + { title: "System", value: "type", icon: "" }, + { title: "Subsystem", value: "subtype", icon: "" }, + { title: "Taxonomy", icon: "", }, + { title: "Superkingdom", value: "Superkingdom", icon: "" }, + { title: "", value: "phylum", icon: "" }, + { title: "", value: "order", icon: "" }, + { title: "", value: "family", icon: "" }, + { title: "", value: "genus", icon: "" }, + { title: "", value: "species", icon: "" }, ]) const availableTaxo: Ref<string[]> = ref([ "species", -- GitLab