mirror of
https://github.com/modrinth/code.git
synced 2026-08-28 10:34:53 +00:00
feat: implement depends on search filter
This commit is contained in:
@@ -32,12 +32,13 @@ export type ProjectType =
|
|||||||
| 'plugin'
|
| 'plugin'
|
||||||
| 'server'
|
| 'server'
|
||||||
|
|
||||||
interface SearchHit {
|
export interface SearchHit {
|
||||||
project_id: string
|
project_id: string
|
||||||
title: string
|
title: string
|
||||||
icon_url?: string
|
icon_url?: string
|
||||||
project_type: string
|
project_type: string
|
||||||
slug: string
|
slug: string
|
||||||
|
author?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
|
|||||||
@@ -37,13 +37,16 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { BanIcon, LockIcon, XCircleIcon, XIcon } from '@modrinth/assets'
|
import { BanIcon, LockIcon, XCircleIcon, XIcon } from '@modrinth/assets'
|
||||||
|
import { useQuery } from '@tanstack/vue-query'
|
||||||
import { computed, type ComputedRef } from 'vue'
|
import { computed, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
|
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
|
||||||
|
import { injectModrinthClient } from '../../providers'
|
||||||
import type { FilterOption, FilterType, FilterValue } from '../../utils/search'
|
import type { FilterOption, FilterType, FilterValue } from '../../utils/search'
|
||||||
import TagItem from '../base/TagItem.vue'
|
import TagItem from '../base/TagItem.vue'
|
||||||
|
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
|
const { labrinth } = injectModrinthClient()
|
||||||
|
|
||||||
const selectedFilters = defineModel<FilterValue[]>('selectedFilters', { required: true })
|
const selectedFilters = defineModel<FilterValue[]>('selectedFilters', { required: true })
|
||||||
|
|
||||||
@@ -58,6 +61,10 @@ const defaultProvidedMessage = defineMessage({
|
|||||||
id: 'search.filter.locked.default',
|
id: 'search.filter.locked.default',
|
||||||
defaultMessage: 'Filter locked',
|
defaultMessage: 'Filter locked',
|
||||||
})
|
})
|
||||||
|
const dependentProjectMessage = defineMessage({
|
||||||
|
id: 'search.filter.dependent_project',
|
||||||
|
defaultMessage: 'Depends on: {project}',
|
||||||
|
})
|
||||||
|
|
||||||
type Item = {
|
type Item = {
|
||||||
type: string
|
type: string
|
||||||
@@ -67,13 +74,39 @@ type Item = {
|
|||||||
provided: boolean
|
provided: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dependentProjectIds = computed(() =>
|
||||||
|
[
|
||||||
|
...new Set(
|
||||||
|
[...selectedFilters.value, ...props.providedFilters]
|
||||||
|
.filter((filter) => filter.type === 'compatible_dependency_project_ids')
|
||||||
|
.map((filter) => filter.option),
|
||||||
|
),
|
||||||
|
].sort(),
|
||||||
|
)
|
||||||
|
|
||||||
|
const { data: dependentProjects } = useQuery({
|
||||||
|
queryKey: computed(() => [
|
||||||
|
'search-filter-control',
|
||||||
|
'dependent-projects',
|
||||||
|
dependentProjectIds.value,
|
||||||
|
]),
|
||||||
|
queryFn: () => labrinth.projects_v2.getMultiple(dependentProjectIds.value),
|
||||||
|
enabled: computed(() => dependentProjectIds.value.length > 0),
|
||||||
|
placeholderData: [],
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const dependentProjectNames = computed(
|
||||||
|
() => new Map(dependentProjects.value?.map((project) => [project.id, project.title]) ?? []),
|
||||||
|
)
|
||||||
|
|
||||||
function filterMatches(type: FilterType, option: FilterOption, list: FilterValue[]) {
|
function filterMatches(type: FilterType, option: FilterOption, list: FilterValue[]) {
|
||||||
return list.some((provided) => provided.type === type.id && provided.option === option.id)
|
return list.some((provided) => provided.type === type.id && provided.option === option.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const items: ComputedRef<Item[]> = computed(() => {
|
const items: ComputedRef<Item[]> = computed(() => {
|
||||||
return props.filters.flatMap((type) =>
|
return props.filters.flatMap((type) => {
|
||||||
type.options
|
const optionItems = type.options
|
||||||
.filter(
|
.filter(
|
||||||
(option) =>
|
(option) =>
|
||||||
filterMatches(type, option, selectedFilters.value) ||
|
filterMatches(type, option, selectedFilters.value) ||
|
||||||
@@ -86,8 +119,30 @@ const items: ComputedRef<Item[]> = computed(() => {
|
|||||||
?.negative,
|
?.negative,
|
||||||
provided: filterMatches(type, option, props.providedFilters),
|
provided: filterMatches(type, option, props.providedFilters),
|
||||||
formatted_name: option.formatted_name,
|
formatted_name: option.formatted_name,
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (type.id !== 'compatible_dependency_project_ids') {
|
||||||
|
return optionItems
|
||||||
|
}
|
||||||
|
|
||||||
|
const customValues = [...selectedFilters.value, ...props.providedFilters].filter(
|
||||||
|
(filter) => filter.type === type.id,
|
||||||
|
)
|
||||||
|
return [
|
||||||
|
...optionItems,
|
||||||
|
...customValues.map((filter) => ({
|
||||||
|
type: type.id,
|
||||||
|
option: filter.option,
|
||||||
|
negative: filter.negative,
|
||||||
|
provided: props.providedFilters.some(
|
||||||
|
(provided) => provided.type === type.id && provided.option === filter.option,
|
||||||
|
),
|
||||||
|
formatted_name: formatMessage(dependentProjectMessage, {
|
||||||
|
project: dependentProjectNames.value.get(filter.option) ?? filter.option,
|
||||||
|
}),
|
||||||
})),
|
})),
|
||||||
)
|
]
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedItems = computed(() => items.value.filter((x) => !x.provided))
|
const selectedItems = computed(() => items.value.filter((x) => !x.provided))
|
||||||
|
|||||||
@@ -71,6 +71,48 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else #default>
|
<template v-else #default>
|
||||||
<slot name="prefix" />
|
<slot name="prefix" />
|
||||||
|
<div
|
||||||
|
v-if="filterType.display === 'project'"
|
||||||
|
:class="innerPanelClass ? innerPanelClass : ''"
|
||||||
|
class="flex flex-col gap-3"
|
||||||
|
>
|
||||||
|
<ProjectCombobox
|
||||||
|
v-show="!selectedProjectId || refreshing"
|
||||||
|
ref="projectCombobox"
|
||||||
|
search-placeholder="Search for a project..."
|
||||||
|
:model-value="selectedProjectId"
|
||||||
|
:project-types="selectableProjectTypes"
|
||||||
|
@update:model-value="setSelectedProjectId"
|
||||||
|
/>
|
||||||
|
<template v-if="selectedProjectId && !refreshing">
|
||||||
|
<div class="flex items-center justify-between gap-3 px-2 text-secondary">
|
||||||
|
<span>{{ formatMessage(messages.dependentCount, { count: resultCount ?? 0 }) }}</span>
|
||||||
|
<button
|
||||||
|
class="border-none bg-transparent p-0 text-secondary cursor-pointer hover:text-contrast"
|
||||||
|
@click="setSelectedProjectId(undefined)"
|
||||||
|
>
|
||||||
|
{{ formatMessage(messages.clearFilter) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 rounded-2xl bg-surface-1 p-3">
|
||||||
|
<img
|
||||||
|
v-if="selectedProject?.icon_url"
|
||||||
|
:src="selectedProject.icon_url"
|
||||||
|
:alt="selectedProject.title"
|
||||||
|
class="size-14 shrink-0 rounded-xl object-cover"
|
||||||
|
/>
|
||||||
|
<PackageIcon v-else class="size-14 shrink-0 text-secondary" />
|
||||||
|
<div class="min-w-0">
|
||||||
|
<div class="truncate text-base font-bold text-contrast">
|
||||||
|
{{ selectedProject?.title ?? selectedProjectId }}
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedProject?.author" class="truncate text-sm text-secondary">
|
||||||
|
{{ selectedProject.author }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="filterType.display === 'toggle'"
|
v-if="filterType.display === 'toggle'"
|
||||||
:class="innerPanelClass ? innerPanelClass : ''"
|
:class="innerPanelClass ? innerPanelClass : ''"
|
||||||
@@ -90,7 +132,7 @@
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="filterType.display !== 'toggle'">
|
<template v-if="filterType.display !== 'toggle' && filterType.display !== 'project'">
|
||||||
<StyledInput
|
<StyledInput
|
||||||
v-if="filterType.searchable"
|
v-if="filterType.searchable"
|
||||||
:id="`search-${filterType.id}`"
|
:id="`search-${filterType.id}`"
|
||||||
@@ -206,7 +248,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { BanIcon, DropdownIcon, LockOpenIcon, SearchIcon, UpdatedIcon } from '@modrinth/assets'
|
import {
|
||||||
|
BanIcon,
|
||||||
|
DropdownIcon,
|
||||||
|
LockOpenIcon,
|
||||||
|
PackageIcon,
|
||||||
|
SearchIcon,
|
||||||
|
UpdatedIcon,
|
||||||
|
} from '@modrinth/assets'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
import { defineMessages, useVIntl } from '../../composables/i18n'
|
import { defineMessages, useVIntl } from '../../composables/i18n'
|
||||||
@@ -215,6 +264,10 @@ import Accordion from '../base/Accordion.vue'
|
|||||||
import ButtonStyled from '../base/ButtonStyled.vue'
|
import ButtonStyled from '../base/ButtonStyled.vue'
|
||||||
import Toggle from '../base/Toggle.vue'
|
import Toggle from '../base/Toggle.vue'
|
||||||
import { Checkbox, ScrollablePanel, StyledInput } from '../index'
|
import { Checkbox, ScrollablePanel, StyledInput } from '../index'
|
||||||
|
import ProjectCombobox, {
|
||||||
|
type ProjectType as ProjectComboboxProjectType,
|
||||||
|
type SearchHit,
|
||||||
|
} from '../project/ProjectCombobox.vue'
|
||||||
import SearchFilterGroup from './SearchFilterGroup.vue'
|
import SearchFilterGroup from './SearchFilterGroup.vue'
|
||||||
import SearchFilterOption from './SearchFilterOption.vue'
|
import SearchFilterOption from './SearchFilterOption.vue'
|
||||||
|
|
||||||
@@ -234,6 +287,8 @@ const props = defineProps<{
|
|||||||
innerPanelClass?: string
|
innerPanelClass?: string
|
||||||
openByDefault?: boolean
|
openByDefault?: boolean
|
||||||
providedFilters: FilterValue[]
|
providedFilters: FilterValue[]
|
||||||
|
resultCount?: number
|
||||||
|
refreshing?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -244,6 +299,26 @@ const query = ref('')
|
|||||||
const showMore = ref(false)
|
const showMore = ref(false)
|
||||||
|
|
||||||
const accordion = ref<InstanceType<typeof Accordion> | null>()
|
const accordion = ref<InstanceType<typeof Accordion> | null>()
|
||||||
|
const projectCombobox = ref<{ selectedProject: SearchHit | null } | null>(null)
|
||||||
|
const selectableProjectTypes: ProjectComboboxProjectType[] = [
|
||||||
|
'mod',
|
||||||
|
'modpack',
|
||||||
|
'resourcepack',
|
||||||
|
'shader',
|
||||||
|
'datapack',
|
||||||
|
'plugin',
|
||||||
|
]
|
||||||
|
const selectedProject = computed(() => projectCombobox.value?.selectedProject ?? null)
|
||||||
|
const selectedProjectId = computed(
|
||||||
|
() => selectedFilters.value.find((filter) => filter.type === props.filterType.id)?.option,
|
||||||
|
)
|
||||||
|
|
||||||
|
function setSelectedProjectId(projectId: string | undefined) {
|
||||||
|
const otherFilters = selectedFilters.value.filter((filter) => filter.type !== props.filterType.id)
|
||||||
|
selectedFilters.value = projectId
|
||||||
|
? [...otherFilters, { type: props.filterType.id, option: projectId }]
|
||||||
|
: otherFilters
|
||||||
|
}
|
||||||
|
|
||||||
const selectedFilterOptions = computed(() =>
|
const selectedFilterOptions = computed(() =>
|
||||||
props.filterType.options.filter((option) =>
|
props.filterType.options.filter((option) =>
|
||||||
@@ -397,6 +472,14 @@ function clearFilters() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
clearFilter: {
|
||||||
|
id: 'search.filter.clear',
|
||||||
|
defaultMessage: 'Clear',
|
||||||
|
},
|
||||||
|
dependentCount: {
|
||||||
|
id: 'search.filter.dependent_count',
|
||||||
|
defaultMessage: '{count, plural, one {# dependent} other {# dependents}}',
|
||||||
|
},
|
||||||
searchPlaceholder: {
|
searchPlaceholder: {
|
||||||
id: 'search.filter.option.search.placeholder',
|
id: 'search.filter.option.search.placeholder',
|
||||||
defaultMessage: 'Search...',
|
defaultMessage: 'Search...',
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export interface BrowseSearchState {
|
|||||||
effectiveCurrentSortType: Ref<SortType>
|
effectiveCurrentSortType: Ref<SortType>
|
||||||
|
|
||||||
loading: Ref<boolean>
|
loading: Ref<boolean>
|
||||||
|
refreshing: Ref<boolean>
|
||||||
projectHits: ShallowRef<BrowseSearchResponse['projectHits']>
|
projectHits: ShallowRef<BrowseSearchResponse['projectHits']>
|
||||||
serverHits: ShallowRef<BrowseSearchResponse['serverHits']>
|
serverHits: ShallowRef<BrowseSearchResponse['serverHits']>
|
||||||
totalHits: Ref<number>
|
totalHits: Ref<number>
|
||||||
@@ -172,6 +173,7 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
])
|
])
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
|
const refreshing = ref(false)
|
||||||
const projectHits = shallowRef<BrowseSearchResponse['projectHits']>([])
|
const projectHits = shallowRef<BrowseSearchResponse['projectHits']>([])
|
||||||
const serverHits = shallowRef<BrowseSearchResponse['serverHits']>([])
|
const serverHits = shallowRef<BrowseSearchResponse['serverHits']>([])
|
||||||
const totalHits = ref(0)
|
const totalHits = ref(0)
|
||||||
@@ -205,6 +207,7 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
)
|
)
|
||||||
|
|
||||||
watch(effectiveRequestParams, (newVal, oldVal) => {
|
watch(effectiveRequestParams, (newVal, oldVal) => {
|
||||||
|
refreshing.value = true
|
||||||
debug('effectiveRequestParams changed', {
|
debug('effectiveRequestParams changed', {
|
||||||
from: oldVal?.substring(0, 80),
|
from: oldVal?.substring(0, 80),
|
||||||
to: newVal?.substring(0, 80),
|
to: newVal?.substring(0, 80),
|
||||||
@@ -217,6 +220,7 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
|
|
||||||
async function refreshSearch() {
|
async function refreshSearch() {
|
||||||
const version = ++searchVersion
|
const version = ++searchVersion
|
||||||
|
refreshing.value = true
|
||||||
debug('refreshSearch start', {
|
debug('refreshSearch start', {
|
||||||
version,
|
version,
|
||||||
projectType: options.projectType.value,
|
projectType: options.projectType.value,
|
||||||
@@ -253,11 +257,13 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
|
|
||||||
updateUrlParams()
|
updateUrlParams()
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
refreshing.value = false
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug('refreshSearch error', err)
|
debug('refreshSearch error', err)
|
||||||
console.error('Browse search error:', err)
|
console.error('Browse search error:', err)
|
||||||
if (version === searchVersion) {
|
if (version === searchVersion) {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
refreshing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,6 +329,7 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
effectiveSortTypes,
|
effectiveSortTypes,
|
||||||
effectiveCurrentSortType,
|
effectiveCurrentSortType,
|
||||||
loading,
|
loading,
|
||||||
|
refreshing,
|
||||||
projectHits,
|
projectHits,
|
||||||
serverHits,
|
serverHits,
|
||||||
totalHits,
|
totalHits,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export interface BrowseManagerContext {
|
|||||||
effectiveSortTypes: ComputedRef<readonly SortType[]>
|
effectiveSortTypes: ComputedRef<readonly SortType[]>
|
||||||
effectiveCurrentSortType: Ref<SortType>
|
effectiveCurrentSortType: Ref<SortType>
|
||||||
loading: Ref<boolean>
|
loading: Ref<boolean>
|
||||||
|
refreshing: Ref<boolean>
|
||||||
projectHits: ShallowRef<BrowseSearchResponse['projectHits']>
|
projectHits: ShallowRef<BrowseSearchResponse['projectHits']>
|
||||||
serverHits: ShallowRef<BrowseSearchResponse['serverHits']>
|
serverHits: ShallowRef<BrowseSearchResponse['serverHits']>
|
||||||
totalHits: Ref<number>
|
totalHits: Ref<number>
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ function getFilterOpenByDefault(filterId: string): boolean {
|
|||||||
v-model:overridden-provided-filter-types="ctx.overriddenProvidedFilterTypes.value"
|
v-model:overridden-provided-filter-types="ctx.overriddenProvidedFilterTypes.value"
|
||||||
:provided-filters="ctx.providedFilters?.value ?? []"
|
:provided-filters="ctx.providedFilters?.value ?? []"
|
||||||
:filter-type="filter"
|
:filter-type="filter"
|
||||||
|
:result-count="ctx.totalHits.value"
|
||||||
|
:refreshing="ctx.refreshing.value"
|
||||||
:class="filterClass"
|
:class="filterClass"
|
||||||
:button-class="buttonClass"
|
:button-class="buttonClass"
|
||||||
:content-class="contentClass"
|
:content-class="contentClass"
|
||||||
|
|||||||
@@ -3548,6 +3548,15 @@
|
|||||||
"s.bg": {
|
"s.bg": {
|
||||||
"defaultMessage": "Background task running"
|
"defaultMessage": "Background task running"
|
||||||
},
|
},
|
||||||
|
"search.filter.clear": {
|
||||||
|
"defaultMessage": "Clear"
|
||||||
|
},
|
||||||
|
"search.filter.dependent_count": {
|
||||||
|
"defaultMessage": "{count, plural, one {# dependent} other {# dependents}}"
|
||||||
|
},
|
||||||
|
"search.filter.dependent_project": {
|
||||||
|
"defaultMessage": "Depends on: {project}"
|
||||||
|
},
|
||||||
"search.filter.locked.default": {
|
"search.filter.locked.default": {
|
||||||
"defaultMessage": "Filter locked"
|
"defaultMessage": "Filter locked"
|
||||||
},
|
},
|
||||||
@@ -3590,6 +3599,9 @@
|
|||||||
"search.filter_type.advanced.exclude_plugin": {
|
"search.filter_type.advanced.exclude_plugin": {
|
||||||
"defaultMessage": "Exclude plugins"
|
"defaultMessage": "Exclude plugins"
|
||||||
},
|
},
|
||||||
|
"search.filter_type.compatible_dependency_project_ids": {
|
||||||
|
"defaultMessage": "Depends on"
|
||||||
|
},
|
||||||
"search.filter_type.environment": {
|
"search.filter_type.environment": {
|
||||||
"defaultMessage": "Environment"
|
"defaultMessage": "Environment"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,10 +43,11 @@ export type FilterType = {
|
|||||||
}[]
|
}[]
|
||||||
searchable: boolean
|
searchable: boolean
|
||||||
allows_custom_options?: 'and' | 'or'
|
allows_custom_options?: 'and' | 'or'
|
||||||
|
custom_option_field?: string
|
||||||
ordering?: number
|
ordering?: number
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
display: 'all' | 'scrollable' | 'none' | 'toggle'
|
display: 'all' | 'scrollable' | 'none' | 'project' | 'toggle'
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
display: 'expandable'
|
display: 'expandable'
|
||||||
@@ -472,6 +473,24 @@ export function useSearch(
|
|||||||
options: [],
|
options: [],
|
||||||
allows_custom_options: 'and',
|
allows_custom_options: 'and',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'compatible_dependency_project_ids',
|
||||||
|
formatted_name: formatMessage(
|
||||||
|
defineMessage({
|
||||||
|
id: 'search.filter_type.compatible_dependency_project_ids',
|
||||||
|
defaultMessage: 'Depends on',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
supported_project_types: ALL_PROJECT_TYPES,
|
||||||
|
query_param: 'dep',
|
||||||
|
supports_negative_filter: false,
|
||||||
|
display: 'project',
|
||||||
|
searchable: false,
|
||||||
|
options: [],
|
||||||
|
allows_custom_options: 'and',
|
||||||
|
custom_option_field: 'compatible_dependency_project_ids',
|
||||||
|
ordering: -999,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'advanced',
|
id: 'advanced',
|
||||||
formatted_name: formatMessage(
|
formatted_name: formatMessage(
|
||||||
@@ -533,7 +552,9 @@ export function useSearch(
|
|||||||
formatted_name: filterValue.option,
|
formatted_name: filterValue.option,
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
method: type.allows_custom_options,
|
method: type.allows_custom_options,
|
||||||
value: filterValue.option,
|
value: type.custom_option_field
|
||||||
|
? `${type.custom_option_field}:${filterValue.option}`
|
||||||
|
: filterValue.option,
|
||||||
}
|
}
|
||||||
} else if (!option) {
|
} else if (!option) {
|
||||||
console.error(`Filter option ${filterValue.option} not found`)
|
console.error(`Filter option ${filterValue.option} not found`)
|
||||||
@@ -771,8 +792,8 @@ export function useSearch(
|
|||||||
currentFilters.value.forEach((filterValue) => {
|
currentFilters.value.forEach((filterValue) => {
|
||||||
const type = filters.value.find((type) => type.id === filterValue.type)
|
const type = filters.value.find((type) => type.id === filterValue.type)
|
||||||
const option = type?.options.find((option) => option.id === filterValue.option)
|
const option = type?.options.find((option) => option.id === filterValue.option)
|
||||||
if (type && option) {
|
if (type && (option || type.allows_custom_options)) {
|
||||||
const value = getOptionValue(option, filterValue.negative)
|
const value = option ? getOptionValue(option, filterValue.negative) : filterValue.option
|
||||||
if (items[type.query_param]) {
|
if (items[type.query_param]) {
|
||||||
items[type.query_param].push(value)
|
items[type.query_param].push(value)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user