Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
W
Wiki
Manage
Activity
Members
Labels
Plan
Issues
53
Issue boards
Milestones
Wiki
Code
Merge requests
6
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
MDM Lab
Wiki
Merge requests
!186
Refactor facet autocomplete
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Refactor facet autocomplete
refactor-facet-autocomplete
into
dev
Overview
0
Commits
36
Pipelines
24
Changes
21
Merged
Remi PLANEL
requested to merge
refactor-facet-autocomplete
into
dev
1 year ago
Overview
0
Commits
36
Pipelines
24
Changes
1
Expand
Better code structure
Add OR between filters
0
0
Merge request reports
Viewing commit
d42368ed
Prev
Next
Show latest version
1 file
+
8
−
2
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
d42368ed
add an autocomple hint
· d42368ed
Remi PLANEL
authored
1 year ago
components/AutocompleteMeiliFacets.vue
0 → 100644
+
255
−
0
Options
<
script
setup
lang=
"ts"
>
import
{
filter
}
from
'
@observablehq/plot
'
export
interface
FilterItem
{
type
:
'
facet
'
|
'
innerOperator
'
|
'
outerOperator
'
|
'
value
'
value
:
string
title
:
string
count
?:
number
deletable
:
boolean
props
:
Record
<
string
,
any
>
}
export
interface
FacetItem
{
title
:
string
value
:
string
type
:
"
facet
"
icon
?:
string
count
?:
number
}
export
interface
OperatorItem
{
title
:
string
,
type
:
'
operator
'
}
export
interface
FacetCategory
{
title
:
string
type
:
"
subheader
"
}
export
interface
FacetDivider
{
type
:
"
divider
"
}
export
type
FacetInputItem
=
FacetItem
|
FacetCategory
|
FacetDivider
export
interface
Props
{
db
:
string
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
'
,
"
meiliFilters
"
])
const
filterId
=
ref
<
number
>
(
0
)
const
props
=
withDefaults
(
defineProps
<
Props
>
(),
{
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 { result: msResult } = useMeiliSearch(props.db)
const
isAutocompleteFocused
=
ref
<
boolean
>
(
false
)
// const facetDistribution: Ref
<
Record
<
string
,
Record
<
string
,
number
>>>
=
useState
(
'
facetDistribution
'
)
const
autocompleteProps
=
computed
(()
=>
{
return
{
...
props
.
autocompleteProps
,
items
:
toValue
(
autocompleteItems
)
}
})
const
filterStep
=
computed
(()
=>
{
const
toValFilterItems
=
toValue
(
props
.
modelValue
)
if
(
toValFilterItems
!==
undefined
)
{
return
toValFilterItems
.
length
%
4
}
})
const
innerOperatorItems
=
ref
<
FilterItem
[]
>
([
{
type
:
"
innerOperator
"
,
value
:
'
=
'
,
title
:
"
is
"
,
deletable
:
false
,
props
:
{
type
:
"
innerOperator
"
,
deletable
:
false
}
},
{
type
:
"
innerOperator
"
,
value
:
'
!=
'
,
title
:
"
is not
"
,
deletable
:
false
,
props
:
{
type
:
"
innerOperator
"
,
deletable
:
false
}
},
])
const
outerOperatorItems
=
ref
<
FilterItem
[]
>
([
{
type
:
"
outerOperator
"
,
value
:
'
AND
'
,
title
:
"
AND
"
,
deletable
:
false
,
props
:
{
type
:
"
outerOperator
"
,
deletable
:
false
}
},
{
type
:
"
outerOperator
"
,
value
:
'
OR
'
,
title
:
"
OR
"
,
deletable
:
false
,
props
:
{
type
:
"
outerOperator
"
,
deletable
:
false
}
},
])
const
autocompleteItems
=
computed
(()
=>
{
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
}
-
${
filterId
.
value
}
`
,
title
:
facetItem
.
title
,
deletable
:
false
,
icon
:
facetItem
?.
icon
,
count
:
facetItem
?.
count
,
props
:
{
deletable
:
false
,
type
:
"
facet
"
}
}
case
"
subheader
"
:
return
{
type
:
"
subheader
"
,
title
:
facetItem
.
title
,
deletable
:
false
,
props
:
{
type
:
"
subheader
"
}
}
case
"
divider
"
:
return
{
type
:
"
divider
"
}
default
:
break
;
}
})
}
if
(
filterStep
.
value
===
1
)
{
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
]
const
facetDistri
=
toValue
(
props
.
facetDistribution
)
return
facetDistri
?.[
sanitizedValue
]
?
Object
.
entries
(
facetDistri
[
sanitizedValue
]).
map
(([
key
,
val
])
=>
{
return
{
type
:
"
value
"
,
value
:
`
${
key
}
-
${
filterId
.
value
}
`
,
title
:
key
,
count
:
val
,
deletable
:
true
,
props
:
{
type
:
"
value
"
,
count
:
val
,
deletable
:
true
}
}
})
:
[]
}
}
if
(
filterStep
.
value
===
3
)
{
filterId
.
value
++
return
outerOperatorItems
.
value
.
map
(
it
=>
{
return
{
...
it
,
value
:
`
${
it
.
value
}
-
${
filterId
.
value
}
`
,
}
})
}
})
const
hasFacetDistribution
=
computed
(()
=>
{
const
toValFacetDistribution
=
toValue
(
props
.
facetDistribution
)
return
toValFacetDistribution
!==
undefined
&&
Object
.
keys
(
toValFacetDistribution
).
length
>
0
})
function
updateAutocompleteFocused
(
isFocused
:
boolean
)
{
isAutocompleteFocused
.
value
=
isFocused
}
function
emitUpdateModelValue
(
filters
:
MaybeRef
<
FilterItem
[]
|
undefined
>
)
{
emit
(
'
update:modelValue
'
,
toValue
(
filters
))
}
function
clearFilters
()
{
emitUpdateModelValue
(
undefined
)
}
function
deleteOneFilter
(
index
:
number
)
{
const
toValFilterItems
=
toValue
(
props
.
modelValue
)
// check if the next item is an outeroperator
const
nextFilterItem
=
toValFilterItems
?.
slice
(
index
+
1
,
index
+
2
)
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
)
}
else
{
toValFilterItems
?.
splice
(
index
-
2
,
3
)
}
emitUpdateModelValue
(
toValFilterItems
)
}
function
isItemFilter
(
type
:
string
|
undefined
)
{
return
type
===
"
facet
"
||
type
===
"
innerOperator
"
||
type
===
"
outerOperator
"
||
type
===
"
value
"
}
const
hint
=
ref
<
string
>
(
'
All <span class="font-weight-bold">OR</span> in a row are grouped together. Example: <span class="font-weight-bold">brex OR avs AND Archea</span> ⇒ <span class="font-weight-bold">(brex OR avs) AND Archea</span>
'
)
</
script
>
<
template
>
<v-autocomplete
:model-value=
"props.modelValue"
@
click:clear=
"clearFilters"
v-bind=
"autocompleteProps"
:hint=
"hint"
persistent-hint
@
update:focused=
"updateAutocompleteFocused"
@
update:modelValue=
"emitUpdateModelValue"
:loading=
"!hasFacetDistribution"
:disabled=
"!hasFacetDistribution"
>
<template
#message
="
{ message }">
<span
v-html=
"message"
></span>
</
template
>
<
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"
:subtitle="item.raw?.count ? item.raw.count : ''" :value="props.value">
</v-list-item>
<v-divider
v-if=
"item.raw.type === 'divider'"
></v-divider>
<v-list-subheader
v-if=
"item.raw.type === 'subheader'"
:title=
"item.raw.title"
></v-list-subheader>
</
template
>
<
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 #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