It is possible to register a custom filter and use it as a DisplayFilter for Dashboards or search modals.
At the moment there are 2 types of custom filters
Hint: If you want to create a filter with metadata, make sure they are setup correctly in the ElasticSearch index, using config: {index: true}
on the metadata property defined in the content type config.
Custom List v2 Filter
Example filter using static options
liEditor.searchFilters.registerListV2('simpleV2Filter', {
datasource: {
fetch ({user}) {
return [{
label: {en: 'Published Articles', de: 'Publizierte Artikel'},
filter: {key: 'lastPublicationId', exists: true}
},
{
label: {en: 'My Articles by updatedAt', de: 'Meine Artikel nach updatedAt'},
sort: '-updatedAt',
filter: {key: 'ownerId', term: user.id}
}]
}
},
// 'mount()' is optional since release-2023-09
mount ({data, filter}) {
filter.options = data
}
})
Example multi value filter
image
liEditor.searchFilters.registerListV2('multiSelectV2Filter', {
multiple: true, // allow multiple selections
label: {en: 'Multi Select', de: 'Mehrfachauswahl'},
datasource: {
fetch ({user}) {
return [{
label: {en: 'Published Articles', de: 'Publizierte Artikel'},
filter: {key: 'lastPublicationId', exists: true}
},
{
label: {en: 'My Articles by updatedAt', de: 'Meine Artikel nach updatedAt'},
sort: '-updatedAt',
filter: {key: 'ownerId', term: user.id}
}]
}
},
// 'mount()' is optional since release-2023-09
mount ({data, filter}) {
filter.options = data
}
})
The selected values are OR
combined in the search query.
Request payload if both filters from above are selected:
[
...,
{ "or": [
{ "key": "lastPublicationId", "exists": true },
{ "key": "ownerId", "term":1 }
]}
]
Example filter using async data fetching
searchFilters.registerListV2
registers an object where you can configure a filter object which is used to render the search UI.
Process
datasource.fetch
fetch data async from a remote service or create a list of filter itemsmount
- configure the filter object
liEditor.searchFilters.registerListV2('contentTypeV2Filter', {
datasource: {
// fetch data and inject response into mount function
async fetch ({project, user, server, config}) {
const host = server.host
const channelId = project.defaultChannel.id
const uri = `${host}/channel-configs/properties?channelId=${channelId}&properties=contentTypes`
const response = await window.fetch(uri, {
method: 'GET',
headers: new window.Headers({
'Content-Type': 'application/json',
'Authorization': `Bearer ${server.accessToken}`
})
})
// only succeed on status codes 200 - 299
if (!response.ok) throw new Error('contentTypeV2Filter was not able to fetch data')
return response.json()
}
},
// Mount a search filter (search behaviour, display options)
//
// @param data injected result from datasource.fetch
//
// @example options = [
// {
// label: 'Regular Article',
// filter: {key: 'contentType', term: 'regular'}
// },
// {
// label: 'Page',
// filter: {key: 'contentType', term: 'page'},
// isDefault: true
// }
// ]
async mount ({data, filter}) {
const options = data.contentTypes.map((ct) => {
return {
label: ct.info.label,
// these props are used for creating a search request (see 'Filter Query Types' link below)
filter: {key: 'contentType', term: ct.handle}
}
})
filter.options = options
}
})
Hint: Look into Filter Query Types to find possible {type, value}
combinations for the filter.options
in the mount
function.
isDefault option
When isDefault: true
(see example above), the default option will be added to the search query by default. As soon as one selects a filter manually, the default filter option will be ignored.
Custom Vue Component Filter
Filters for the media-library need to define the dataType
// before release-2023-07
$emit('update:filter', {type: 'metadata', key:'transformed', dataType: 'boolean', value: true})
// after release-2023-07, uses the new Search DSL
$emit('update:filter', {filter: {key:'metadata.transformed', term: true}})
The value of the emitted filter
property must be an object. If you need to combine multiple properties these should be assigned to an and
, or
, or not
property within the filter object:
$emit('update:filter', {
filter: {
and: [
{
key: 'visiblePublicationDate',
range: {
gte: '2023-01-01T00:00:00.000Z',
lte: '2023-01-01T23:59:59.999Z'
}
},
{
key: 'lastPublicationDate',
exists: true
}
]
}
})
// In case the DisplayFilter needs to configure a sort option, use the sort atribute
// '-' indicates descending order
// No prefix indicates ascending order
$emit('update:filter', {sort: '-createdAt'})
Example
vueComponentRegistry.registerComponent({type: 'searchFilter'})
registers a Vue component as filter for the search UI. Below you can see a minimal example:
liEditor.vueComponentRegistry.registerComponent({
type: 'searchFilter',
name: 'customFilter',
component: require('./filters/custom-filter.vue').default
})
After registering the filter, the vue component will recieve a prop called filter
and the upstream-editor has some logic behind the scenes. For example the filter is written onto the localStorage so it persists through refreshing or navigating and triggers the search, or is cleared after resetting the filter settings.
<template>
<!-- the 'update:filter' event is required -->
<div
@click="$emit('update:filter', {filter: {key: 'updatedAt', range: {gte: 'now-24h'}})">
Filter logic
</div>
</template>
<style lang="scss" scoped>
.my-css-class {
}
</style>
<script>
export default {
name: 'customFilter',
props: {
// synced with it's parent and the value in the localStorage
// updated via $emit('update:filter', {...data})
filter: {
type: Object,
default () {}
},
// the config property defined when configuring the filter on a dashboard
config: {
type: Object,
required: true
},
// added in release-2023-11. Use it to change the UI of your filter when the user
// set a value
inDefaultState: {
type: Boolean,
required: true
}
}
}
</script>