diff --git a/components/AutocompleteMeiliFacets.vue b/components/AutocompleteMeiliFacets.vue
index b4285d38e829181179475c498001075bd5c4b154..97b911c9ce3100d5f9c773713eee37a3f600bc1f 100644
--- a/components/AutocompleteMeiliFacets.vue
+++ b/components/AutocompleteMeiliFacets.vue
@@ -1,4 +1,6 @@
<script setup lang="ts">
+import { filter } from '@observablehq/plot'
+
export interface FilterItem {
type: 'facet' | 'innerOperator' | 'outerOperator' | 'value' | 'text'
value: string
@@ -32,34 +34,54 @@ export interface FacetDivider {
export type FacetInputItem = FacetItem | FacetCategory | FacetDivider
+
export interface Props {
db: string
- modelValue: string | undefined
- facets: MaybeRef<FacetInputItem[]>
+ modelValue: FilterItem[] | undefined
+ facets: MaybeRef<FacetInputItem[] | undefined>
facetDistribution: MaybeRef<Record<string, Record<string, number>> | undefined>
+ isValidFilters?: MaybeRef<boolean>
+ autocompleteProps?: Record<string, any>
+
}
-const emit = defineEmits(['update:modelValue'])
+
+const emit = defineEmits(['update:modelValue', "meiliFilters"])
+const filterId = ref<number>(0)
const props = withDefaults(defineProps<Props>(), {
- modelValue: ""
+ modelValue: undefined,
+ autocompleteProps: () => {
+ return {
+ chips: true,
+ clearable: true,
+ multiple: true,
+ "auto-select-first": true,
+ "return-object": true,
+ "prepend-inner-icon": "md:filter_alt",
+ "hide-details": "auto",
+ "item-value": "value", "item-title": "title",
+ label: "Filter results...",
+ "single-line": true,
+
+ }
+ },
+ isValidFilters: false
});
-const filterItems = ref<FilterItem[] | undefined>(undefined)
// const { result: msResult } = useMeiliSearch(props.db)
const isAutocompleteFocused = ref<boolean>(false)
// const facetDistribution: Ref<Record<string, Record<string, number>>> = useState('facetDistribution')
-const computedFacets = computed(() => {
- const toValFacetDistri = toValue(props.facetDistribution)
- if (toValFacetDistri) {
- return Object.keys(toValFacetDistri)
- }
- else { return undefined }
-})
+const autocompleteProps = computed(() => {
+ return {
+ ...props.autocompleteProps,
+ items: toValue(autocompleteItems)
+ }
+})
const filterStep = computed(() => {
- const toValFilterItems = toValue(filterItems)
+ const toValFilterItems = toValue(props.modelValue)
if (toValFilterItems !== undefined) {
return toValFilterItems.length % 4
}
@@ -94,15 +116,16 @@ const outerOperatorItems = ref<FilterItem[]>([
])
const autocompleteItems = computed(() => {
- const toValFilterItems = toValue(filterItems)
- const index = toValFilterItems?.length ?? 0
+ const toValFilterItems = toValue(props.modelValue)
+ // const index = toValFilterItems?.length ?? 0
if (filterStep.value === undefined || filterStep.value === 0) {
+ filterId.value++
return toValue(props.facets)?.map(facetItem => {
switch (facetItem.type) {
case "facet":
return {
type: "facet",
- value: `${facetItem.value}-${index}`,
+ value: `${facetItem.value}-${filterId.value}`,
title: facetItem.title,
deletable: false,
icon: facetItem?.icon,
@@ -131,20 +154,20 @@ const autocompleteItems = computed(() => {
})
}
if (filterStep.value === 1) {
- return innerOperatorItems.value.map(it => { return { ...it, value: `${it.value}-${index}`, } })
+ filterId.value++
+ return innerOperatorItems.value.map(it => { return { ...it, value: `${it.value}-${filterId.value}`, } })
}
if (filterStep.value === 2) {
+ filterId.value++
+
// get the facet value
if (Array.isArray(toValFilterItems)) {
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 = toValue(props.facetDistribution)
- // console.log(facetDistri)
return facetDistri?.[sanitizedValue] ? Object.entries(facetDistri[sanitizedValue]).map(([key, val]) => {
return {
- type: "value", value: `${key}-${index}`, title: key, count: val, deletable: true, props: {
+ type: "value", value: `${key}-${filterId.value}`, title: key, count: val, deletable: true, props: {
type: "value", count: val, deletable: true
}
}
@@ -152,78 +175,41 @@ const autocompleteItems = computed(() => {
}
}
if (filterStep.value === 3) {
- return outerOperatorItems.value.map(it => { return { ...it, value: `${it.value}-${index}`, } })
+ filterId.value++
+ return outerOperatorItems.value.map(it => { return { ...it, value: `${it.value}-${filterId.value}`, } })
}
})
-const lastFilterItem = computed(() => {
- const toValFilterItems = toValue(filterItems)
- if (toValFilterItems !== undefined) {
- return toValFilterItems.slice(-1)[0]
- }
-})
-const isValidFilters = computed(() => {
- const toValFilterStep = toValue(filterStep)
-
- const toValFilterItems = toValue(filterItems)
- if (toValFilterItems === undefined || toValFilterItems?.length === 0) {
- return true
- }
- else {
- const toValLastFilterItem = toValue(lastFilterItem)
- if (toValLastFilterItem !== undefined) {
- return toValLastFilterItem.type === 'value'
- // && isAutocompleteFocused.value === false
- // || (toValFilterStep === 0 && toValLastFilterItem.type === "outerOperator" && toValLastFilterItem.value.split("-")[0] === "AND")
- }
- }
- return false
-})
-
-function toMeiliFilter(filterItems: FilterItem[] | undefined) {
- if (filterItems !== undefined) {
- const tmpFilterItems = [...filterItems]
- if (tmpFilterItems.length % 4 === 0) {
- tmpFilterItems.splice(-1)
- }
- return tmpFilterItems.map((it, index) => {
- const sanitizedValue = it.value.split("-").slice(0, -1).join("-")
- if ((index + 1) % 4 === 3) {
- return `"${sanitizedValue}"`
- } else if ((index + 1) % 4 === 0) {
- return ` ${sanitizedValue} `
- }
- else {
- return `${sanitizedValue}`
- }
-
- }).join("")
- }
-}
function updateAutocompleteFocused(isFocused: boolean) {
isAutocompleteFocused.value = isFocused
}
-function emitUpdateModelValue() {
- if (toValue(isValidFilters)) {
- const meiliFilter = toMeiliFilter(toValue(filterItems))
- emit('update:modelValue', meiliFilter)
- }
+function emitUpdateModelValue(filters: MaybeRef<FilterItem[] | undefined>) {
+ console.log("dans emit model")
+ console.log(filters)
+
+ // const meiliFilter = toMeiliFilter(toValue(filters))
+ // emit("meiliFilters", meiliFilter)
+ emit('update:modelValue', toValue(filters))
+
}
function clearFilters() {
- filterItems.value = undefined
- emitUpdateModelValue()
+ emitUpdateModelValue(undefined)
}
function deleteOneFilter(index: number) {
- const toValFilterItems = toValue(filterItems)
+ const toValFilterItems = toValue(props.modelValue)
// check if the next item is an outeroperator
const nextFilterItem = toValFilterItems?.slice(index + 1, index + 2)
- if (nextFilterItem?.length === 1 && nextFilterItem[0].type === 'outerOperator') {
+ if (index + 1 === toValFilterItems?.length && toValFilterItems?.length >= 7) {
+ // need to remove the previous outer operator
+ toValFilterItems?.splice(index - 3, 4)
+ }
+ else if (nextFilterItem?.length === 1 && nextFilterItem[0].type === 'outerOperator') {
toValFilterItems?.splice(index - 2, 4)
}
@@ -231,7 +217,7 @@ function deleteOneFilter(index: number) {
toValFilterItems?.splice(index - 2, 3)
}
- emitUpdateModelValue()
+ emitUpdateModelValue(toValFilterItems)
}
function isItemFilter(type: string | undefined) {
@@ -240,10 +226,8 @@ function isItemFilter(type: string | undefined) {
</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:filter_alt" hide-details="auto" single-line
- item-value="value" item-title="title" class="mx-2" @click:clear="clearFilters"
- @update:focused="updateAutocompleteFocused">
+ <v-autocomplete :model-value="props.modelValue" class="mx-2" @click:clear="clearFilters" v-bind="autocompleteProps"
+ @update:focused="updateAutocompleteFocused" @update:modelValue="emitUpdateModelValue">
<template #item="{ props, item }">
<v-list-item v-if="isItemFilter(item?.raw?.type)" v-bind="{ ...props, active: false }" :title="item.title"
:prepend-icon="item?.raw?.icon ? item.raw.icon : undefined"
@@ -256,9 +240,10 @@ function isItemFilter(type: string | undefined) {
<v-chip v-bind="props" :text="item.raw.title" :closable="item.props.deletable"
@click:close="item.props.type === deleteOneFilter(index)"></v-chip>
</template>
- <template #append>
- <v-btn variant="text" icon="md:filter_alt" @click="emitUpdateModelValue" :disabled="!isValidFilters"></v-btn>
- </template>
+ <!-- <template #append>
+ <v-btn variant="text" icon="md:filter_alt" @click="emitUpdateModelValue(props.modelValue)"
+ :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 a5590386e8a745e3304eff81a2213a8f7bc9cd27..7bf896d0681fc244f80960f615d98381f3eb9f13 100644
--- a/components/ServerDbTable.vue
+++ b/components/ServerDbTable.vue
@@ -4,8 +4,9 @@ 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 type { FacetInputItem, FilterItem } from '@/components/AutocompleteMeiliFacets.vue'
import { useMeiliSearch } from "#imports"
+import type { Filter } from "meilisearch";
// import { saveAs } from "file-saver";
export interface SortItem {
key: string,
@@ -21,34 +22,40 @@ export interface NumericalFilter {
export interface NumericalFilterModel extends NumericalFilter {
model: [number, number]
}
+
+
+
+
+
+export interface AutocompleteMeiliFacetProps {
+ db: string
+ facets: FacetInputItem[] | undefined
+ facetDistribution: Record<string, Record<string, number>> | undefined
+
+}
export interface Props {
title?: string
- db?: string
sortBy?: SortItem[]
- facets: MaybeRef<FacetInputItem[]>
numericalFilters?: MaybeRef<string | undefined>
dataTableServerProps: Record<string, any>
columnsToDownload?: MaybeRef<string[] | undefined>
- facetDistribution: MaybeRef<Record<string, Record<string, number>> | undefined>
+ autocompleteMeiliFacetsProps: AutocompleteMeiliFacetProps
}
-export interface FilterItem {
- type: 'facet' | 'operator' | 'value' | 'text'
- value: string
- title: string
- count?: number
- deletable: boolean
- props: Record<string, any>
-}
const props = withDefaults(defineProps<Props>(), {
title: '',
- db: 'refseq',
columnsToDownload: undefined,
sortBy: () => [{ key: "type", order: "asc" }],
- numericalFilters: undefined
-
+ numericalFilters: undefined,
+ autocompleteMeiliFacetsProps: () => {
+ return {
+ db: 'refseq',
+ facetDistribution: undefined,
+ facets: undefined
+ }
+ }
});
// const facetDistribution: Ref<Record<string, Record<string, number>> | undefined> = useState(`refseqFacetDistribution`)
@@ -56,9 +63,8 @@ const props = withDefaults(defineProps<Props>(), {
const slots = useSlots()
const sortByRef = toRef(props.sortBy)
-const facetsRef = toRef(props.facets)
const emit = defineEmits(["refresh:search"])
-const { search: msSearch, result: msResult } = useMeiliSearch(props.db)
+const { search: msSearch, result: msResult } = useMeiliSearch(props.autocompleteMeiliFacetsProps.db)
const search: Ref<string> = ref("");
const filterOrSearch: Ref<FilterItem[] | null> = ref(null)
const hitsPerPage: Ref<number> = ref(25)
@@ -78,7 +84,7 @@ const computedTableHeight = computed(() => {
const pendingDownloadData = ref(false)
-
+// const meiliFilters = ref<string | undefined>(undefined)
const filterInputValues = computed(() => {
if (filterOrSearch.value != null) {
@@ -88,9 +94,6 @@ const filterInputValues = computed(() => {
}
})
-const isFilter = computed(() => {
- return Array.isArray(filterOrSearch.value)
-})
const msSortBy = computed(() => {
if (sortByRef.value.length > 0) {
@@ -119,47 +122,57 @@ const notPaginatedParams = computed(() => {
watch([paginationParams, msSortBy, page], ([newParams, newSort, newPage]) => {
- searchOrFilter()
+ if (toValue(isValidFilters)) {
+ searchOrFilter()
+ }
})
-onMounted(async () => {
+onBeforeMount(async () => {
searchOrFilter()
emitRefreshRes()
})
-const msFilterCompo = ref<string | undefined>(undefined)
+const msFilterCompo = ref<FilterItem[] | undefined>(undefined)
-const msFilter = computed(() => {
- if (isFilter.value && filterInputValues.value !== null && filterInputValues.value?.length % 3 === 0) {
- return filterInputValues.value.map((it, index) => {
+const computedFilter = computed(() => {
+
+
+ const toValFilters = toValue(msFilterCompo)
+ let filtersStr: string | undefined = undefined
+ if (toValFilters !== undefined) {
+ const tmpFilterItems = [...toValFilters]
+ if (tmpFilterItems.length % 4 === 0) {
+ tmpFilterItems.splice(-1)
+ }
+ filtersStr = tmpFilterItems.map((it, index) => {
const sanitizedValue = it.value.split("-").slice(0, -1).join("-")
- if (index >= 1 && (index + 1) % 3 === 1) {
- return ` AND ${sanitizedValue}`
- } else if ((index + 1) % 3 === 0) {
+ if ((index + 1) % 4 === 3) {
return `"${sanitizedValue}"`
- } else {
+ } else if ((index + 1) % 4 === 0) {
+ return ` ${sanitizedValue} `
+ }
+ else {
return `${sanitizedValue}`
}
}).join("")
- } else { return null }
-})
-const computedFilter = computed(() => {
- console.log(toValue(msFilterCompo))
- if (msFilterCompo.value !== null) {
- return [toValue(msFilterCompo), props.numericalFilters].filter(f => f !== undefined && f !== null).join(" AND ")
+
}
+
+ return [filtersStr, props.numericalFilters].filter(f => f !== undefined && f !== null).join(" AND ")
+
})
watch(computedFilter, () => {
+ console.log("dans le watch meilifilters")
console.log(toValue(computedFilter))
- if (toValue(computedFilter) !== undefined || toValue(filterInputValues) === null) {
+ if (toValue(isValidFilters) && (toValue(computedFilter) !== undefined || toValue(filterInputValues) === null)) {
searchOrFilter()
emitRefreshRes()
}
@@ -178,150 +191,98 @@ const throttleSearch = useThrottleFn(async () => {
}, 300)
+const lastFilterItem = computed(() => {
+ const toValFilterItems = toValue(msFilterCompo)
+ if (toValFilterItems !== undefined && Array.isArray(toValFilterItems)) {
+ return toValFilterItems.slice(-1)[0]
+ }
+})
-async function searchOrFilter() {
+const isValidFilters = computed(() => {
+ console.log("dans is valid filter")
+ console.log("idvalidfilters", msFilterCompo)
+ const toValFilterItems = toValue(msFilterCompo)
+ console.log(toValFilterItems)
+ console.log(typeof toValFilterItems)
+ console.log(Array.isArray(toValFilterItems))
- // do something, it will be called at most 1 time per second
- try {
- loading.value = true
- // const q = queryInputValue.value === null ? "" : queryInputValue.value
- const q = search.value
- await msSearch(q, { ...paginationParams.value, filter: toValue(computedFilter), sort: msSortBy.value })
- } catch (error: any) {
- filterError.value = error
- console.log(error)
+ console.log(toValFilterItems?.length)
+
+ if (toValFilterItems === undefined || Array.isArray(toValFilterItems) && toValFilterItems?.length === 0) {
+ return true
}
- finally {
- loading.value = false
+ else {
+ const toValLastFilterItem = toValue(lastFilterItem)
+ console.log("the last filter")
+ console.log(toValFilterItems)
+ if (toValLastFilterItem !== undefined) {
+ console.log(toValLastFilterItem.type)
+ console.log(toValLastFilterItem.type === 'value')
+ return toValLastFilterItem.type === 'value'
+ // && isAutocompleteFocused.value === false
+ // || (toValFilterStep === 0 && toValLastFilterItem.type === "outerOperator" && toValLastFilterItem.value.split("-")[0] === "AND")
+ }
+ }
+ console.log("retrun false")
+ return false
+})
+
+
+async function searchOrFilter() {
+ console.log("dans searchOrFilter")
+ console.log("is valide filter : ", toValue(isValidFilters))
+ if (toValue(isValidFilters)) {
+ // do something, it will be called at most 1 time per second
+ try {
+ loading.value = true
+ // const q = queryInputValue.value === null ? "" : queryInputValue.value
+ const q = search.value
+ await msSearch(q, { ...paginationParams.value, filter: toValue(computedFilter), sort: msSortBy.value })
+ } catch (error: any) {
+ filterError.value = error
+ console.log(error)
+ }
+ finally {
+ loading.value = false
+ }
}
}
+
+
function emitRefreshRes() {
const q = search.value
+ console.log("dans le emitrefresh res")
emit("refresh:search", {
- index: props.db,
+ index: props.autocompleteMeiliFacetsProps.db,
query: q,
params: { ...notPaginatedParams.value, filter: toValue(computedFilter), sort: msSortBy.value }
})
}
-function clearFilterOrSearch() {
- filterOrSearch.value = null
- // searchOrFilter()
- // emitRefreshRes()
-
-}
const totalHits = computed(() => {
return toValue(msResult)?.totalHits ?? toValue(msResult)?.estimatedTotalHits ?? 0
})
-const msFacetDistributionParams = computed(() => {
- return { index: props.db, query: "", params: { ...paginationParams.value } }
-})
+
watch(search, () => {
searchOrFilter()
// emitRefreshRes()
})
-watch(msFilterCompo, () => {
- searchOrFilter()
+// watch(msFilterCompo, () => {
+// searchOrFilter()
-})
-const filterStep = computed(() => {
- return filterInputValues.value !== null && filterInputValues.value.length > 0 ? filterInputValues.value?.length % 3 : null
-})
-const operatorItems = ref([
- {
- type: "operator", value: '=', title: "is", deletable: false, props: {
- type: "operator", deletable: false
- }
- }, {
- type: "operator", value: '!=', title: "is not", deletable: false, props: {
- type: "operator",
- deletable: false
- }
- },
-
-])
-
-const autocompleteItems = computed(() => {
- const index = filterOrSearch.value?.length ?? 0
- // console.log(index)
- if (filterStep.value === null || filterStep.value === 0) {
- return toValue(facetsRef).map(facetItem => {
- switch (facetItem.type) {
- case "facet":
- return {
- type: "facet",
- value: `${facetItem.value}-${index}`,
- title: facetItem.title,
- deletable: false,
- props: {
- deletable: false,
- type: "facet"
- }
- }
- case "subheader":
- return {
- type: "subheader",
- title: facetItem.title,
- deletable: false,
- props: {
- type: "subheader"
- }
- }
- default:
- break;
- }
-
- })
- }
- if (filterStep.value === 1) {
- return operatorItems.value.map(it => { return { ...it, value: `${it.value}-${index}`, } })
- }
- if (filterStep.value === 2) {
- // get the facet value
- if (Array.isArray(filterOrSearch.value)) {
- const { type, value } = filterOrSearch.value?.slice(-2, -1)[0]
- const sanitizedValue = value.split("-")[0]
- // console.log("compute new facets")
- const facetDistri = msResult.value?.facetDistribution
- // console.log(facetDistri)
- return facetDistri?.[sanitizedValue] ? Object.entries(facetDistri[sanitizedValue]).map(([key, val]) => {
- return {
- type: "value", value: `${key}-${index}`, title: key, count: val, deletable: true, props: {
- type: "value", count: val, deletable: true
- }
- }
- }) : []
- }
- }
-})
-
-
-
-function selectItem(item) {
- filterOrSearch.value = Array.isArray(filterOrSearch.value) ? [...filterOrSearch.value, item] : [item]
-}
-
-function deleteOneFilter(index: number) {
- if (isFilter.value) {
- filterOrSearch.value?.splice(index - 2, 2)
- }
-}
-
-function clearSearch() {
- search.value = ""
-}
+// })
async function downloadData() {
pendingDownloadData.value = true
try {
const { data } = await useAsyncMeiliSearch({
- index: props.db,
+ index: props.autocompleteMeiliFacetsProps.db,
params: { ...toValue(notPaginatedParams), filter: toValue(computedFilter), sort: toValue(msSortBy) },
query: toValue(search),
})
@@ -365,35 +326,14 @@ function focusedOrBlur(isFocused: boolean) {
prepend-inner-icon="mdi-magnify" single-line clearable :disabled="pendingDownloadData"
class="mx-2" @update:focused="focusedOrBlur"></v-text-field>
</v-toolbar>
- <!-- <v-toolbar>
- <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"
- @click:appendInner="searchOrFilter" class="mx-2" @click:clear="clearFilterOrSearch"
- @update:modelValue="() => clearSearch()">
- <template #chip="{ props, item, index }">
- <v-chip v-bind="props" :text="item.raw.title" :closable="item.props.deletable"
- @click:close="item.props.type === deleteOneFilter(index)"></v-chip>
- </template>
- <template #item="{ props, item }">
- <v-list-item v-bind="{ ...props, active: false, onClick: () => selectItem(item) }"
- :title="item.title" :subtitle="item.raw?.count ? item.raw.count : ''"
- :value="props.value">
-
- </v-list-item>
- </template>
- </v-autocomplete>
- </v-toolbar> -->
<v-toolbar>
- <AutocompleteMeiliFacets v-model="msFilterCompo" :db="props.db" :facets="props.facets"
- :facet-distribution="props.facetDistribution" @update:modelValue="emitRefreshRes">
+ <AutocompleteMeiliFacets v-model:modelValue="msFilterCompo"
+ v-bind="props.autocompleteMeiliFacetsProps" :is-valid-filters="isValidFilters">
</AutocompleteMeiliFacets>
</v-toolbar>
</template>
<template v-else>
<v-toolbar>
-
<v-badge :content="totalHits" color="primary" class="mr-3">
<v-btn prepend-icon="md:download" :loading="pendingDownloadData" variant="text" color="primary"
@click="downloadData()">{{
@@ -401,38 +341,19 @@ function focusedOrBlur(isFocused: boolean) {
</v-btn>
</v-badge>
<v-spacer></v-spacer>
- <v-card variant="flat" color="transparent" :min-width="400" class="mx-2" :rounded="false">
- <v-text-field v-model="search" label="Search..." hide-details="auto"
- :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"
- 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"
- @click:appendInner="searchOrFilter" @click:clear="clearFilterOrSearch"
- @update:modelValue="() => clearSearch()">
- <template #chip="{ props, item, index }">
- <v-chip v-bind="props" :text="item.raw.title" :closable="item.props.deletable"
- @click:close="item.props.type === deleteOneFilter(index)"></v-chip>
- </template>
- <template #item="{ props, item }">
- <v-list-item v-bind="{ ...props, active: false, onClick: () => selectItem(item) }"
- :title="item.title" :subtitle="item.raw?.count ? item.raw.count : ''"
- :value="props.value">
-
- </v-list-item>
- </template>
- </v-autocomplete>
-
- </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"
- :facet-distribution="props.facetDistribution" @update:modelValue="emitRefreshRes">
- </AutocompleteMeiliFacets>
- </v-card>
-
+ <v-col>
+ <v-card variant="flat" color="transparent" :min-width="400" class="mx-2" :rounded="false">
+ <v-text-field v-model="search" label="Search..." hide-details="auto"
+ :disabled="pendingDownloadData" prepend-inner-icon="mdi-magnify" single-line clearable
+ @update:focused="focusedOrBlur"></v-text-field>
+ </v-card>
+ </v-col><v-col>
+ <v-card variant="flat" color="transparent" :min-width="600" class="mx-2" :rounded="false">
+ <AutocompleteMeiliFacets v-model="msFilterCompo" v-bind="props.autocompleteMeiliFacetsProps"
+ :is-valid-filters="isValidFilters">
+ </AutocompleteMeiliFacets>
+ </v-card>
+ </v-col>
</v-toolbar>
</template>
diff --git a/components/content/RefseqDb.vue b/components/content/RefseqDb.vue
index b3e09b3a02244ae1d85a02b51e336a69a09b219e..99d460722b12be1a9a1a31d59984edeec4c4a24f 100644
--- a/components/content/RefseqDb.vue
+++ b/components/content/RefseqDb.vue
@@ -2,13 +2,13 @@
import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure";
import { useDisplay } from "vuetify";
-import type { SortItem } from "@/components/ServerDbTable.vue"
+
import { ServerDbTable } from "#components"
import { useSerialize } from "@/composables/useSerialize";
import { useRasterize } from "@/composables/useRasterize";
import { useDownloadBlob } from '@/composables/useDownloadBlob';
-
+import type { SortItem, AutocompleteMeiliFacetProps } from "@/components/ServerDbTable.vue"
import type { ComponentPublicInstance } from 'vue'
import type { FacetInputItem } from '@/components/AutocompleteMeiliFacets.vue'
@@ -18,27 +18,9 @@ const { width } = useDisplay();
const dbName = ref("refseq")
const scaleTransform: Ref<string[]> = ref([])
-const facetDistribution: Ref<Record<string, Record<string, number>> | undefined> = ref(undefined)
-// await callOnce(async () => {
-
-// console.log("dans le call once")
-// const { data } = await useAsyncMeiliSearch({
-// index: toValue(dbName), query: "", params: {
-// facets: ["*"],
-// filter: [],
-// page: 1,
-// hitsPerPage: 25,
-// }
-// })
-// console.log(data)
-
-
-// facetDistribution.value = toValue(data)?.facetDistribution
-// })
onBeforeMount(async () => {
- console.log("dans le mounted refseq")
const { data } = await useAsyncMeiliSearch({
index: toValue(dbName), query: "", params: {
facets: ["*"],
@@ -47,43 +29,57 @@ onBeforeMount(async () => {
hitsPerPage: 25,
}
})
- console.log(toValue(data))
- facetDistribution.value = toValue(data)?.facetDistribution
+
+ autocompleteMeiliFacetsProps.value.facetDistribution = toValue(data)?.facetDistribution
+
})
const { serialize } = useSerialize()
const { rasterize } = useRasterize()
const { download } = useDownloadBlob()
+const autocompleteMeiliFacetsProps = ref<AutocompleteMeiliFacetProps>({
+ db: toValue(dbName),
+ facets: [
+ { title: "Defense System", type: "subheader" },
+ { title: "System", value: "type", type: "facet", icon: "mdi-virus-outline", },
+ { title: "Subsystem", value: "subtype", type: "facet", icon: "mdi-virus-outline" },
+ { type: "divider" },
+ { title: "Taxonomy", type: "subheader" },
+ { title: "Superkingdom", value: "Superkingdom", type: "facet", icon: "mdi-family-tree" },
+ { title: "Phylum", value: "phylum", type: "facet", icon: "mdi-family-tree" },
+ { title: "Order", value: "order", type: "facet", icon: "mdi-family-tree" },
+ { title: "Family", value: "family", type: "facet", icon: "mdi-family-tree" },
+ { title: "Genus", value: "genus", type: "facet", icon: "mdi-family-tree" },
+ { title: "Species", value: "species", type: "facet", icon: "mdi-family-tree" },
+ { type: "divider" },
+ { title: "Replicon", value: "replicon", type: "facet", icon: "mdi-dna", },
+
+ ],
+ facetDistribution: undefined
+})
+const computedAutocompleteMeiliFacetsProps = computed(() => {
+ const toValFacetDistribution = toValue(autocompleteMeiliFacetsProps).facetDistribution
+ const toValFacets = toValue(autocompleteMeiliFacetsProps).facets
+ if (toValFacetDistribution !== undefined) {
+ return {
+ ...toValue(autocompleteMeiliFacetsProps), facets: toValFacets.map(facet => {
+ if (facet.type === "facet") {
+ const count = toValFacetDistribution?.[facet.value] ? Object.keys(toValFacetDistribution[facet.value]).length : undefined
+ return count ? { ...facet, count } : { ...facet }
+ }
+ else {
+ return { ...facet }
+ }
+ })
+ }
+ }
+ else {
+ return toValue(autocompleteMeiliFacetsProps)
+ }
-const facets = ref<FacetInputItem[]>([
- { title: "Defense System", type: "subheader" },
- { title: "System", value: "type", type: "facet", icon: "mdi-virus-outline", },
- { title: "Subsystem", value: "subtype", type: "facet", icon: "mdi-virus-outline" },
- { type: "divider" },
- { title: "Taxonomy", type: "subheader" },
- { title: "Superkingdom", value: "Superkingdom", type: "facet", icon: "mdi-family-tree" },
- { title: "Phylum", value: "phylum", type: "facet", icon: "mdi-family-tree" },
- { title: "Order", value: "order", type: "facet", icon: "mdi-family-tree" },
- { title: "Family", value: "family", type: "facet", icon: "mdi-family-tree" },
- { title: "Genus", value: "genus", type: "facet", icon: "mdi-family-tree" },
- { title: "Species", value: "species", type: "facet", icon: "mdi-family-tree" },
- { type: "divider" },
- { title: "Replicon", value: "replicon", type: "facet", icon: "mdi-dna", },
-
-])
-
-
-const computedFacets = computed(() => {
- const toValFacetDistribution = toValue(facetDistribution)
- console.log(toValFacetDistribution)
- return toValue(facets).map(facet => {
- const count = toValFacetDistribution?.[facet.value] ? Object.keys(toValFacetDistribution[facet.value]).length : undefined
-
- return count ? { ...facet, count } : { ...facet }
- })
})
const availableTaxo: Ref<string[]> = ref([
@@ -461,9 +457,9 @@ async function downloadPng(component: ComponentPublicInstance | null, filename:
</v-expansion-panel>
</v-expansion-panels>
- <ServerDbTable title="RefSeq" :db="dbName" :sortBy="sortBy" :facets="computedFacets"
- :facet-distribution="facetDistribution" :data-table-server-props="dataTableServerProps"
- @refresh:search="(params) => getAllHits(params)">
+ <ServerDbTable title="RefSeq" :sortBy="sortBy"
+ :autocomplete-meili-facets-props="computedAutocompleteMeiliFacetsProps"
+ :data-table-server-props="dataTableServerProps" @refresh:search="(params) => getAllHits(params)">
<template #[`item.accession_in_sys`]="{ item }">
<CollapsibleChips :items="namesToAccessionChips(item.accession_in_sys)">