feat(filter): add actual label search when autocompleting
This commit is contained in:
parent
9ade917ac4
commit
8fa2f6686a
@ -27,30 +27,6 @@ watch(
|
|||||||
|
|
||||||
const emit = defineEmits(['blur'])
|
const emit = defineEmits(['blur'])
|
||||||
|
|
||||||
const placeholderText = computed(() => {
|
|
||||||
const value = (model.value || '').replace(/[\n\r\t]/gi, ' ')
|
|
||||||
|
|
||||||
if (state.value === 'unfocused') {
|
|
||||||
return value ? '' : props.suggestion
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value || !value.trim()) {
|
|
||||||
return props.suggestion
|
|
||||||
}
|
|
||||||
|
|
||||||
return lookahead()
|
|
||||||
})
|
|
||||||
|
|
||||||
const spacerText = computed(() => {
|
|
||||||
const value = (model.value || '').replace(/[\n\r\t]/gi, ' ')
|
|
||||||
|
|
||||||
if (!value || !value.trim()) {
|
|
||||||
return props.suggestion
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
})
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
options: any[],
|
options: any[],
|
||||||
suggestion?: string,
|
suggestion?: string,
|
||||||
@ -161,14 +137,10 @@ function onUpdateField(e) {
|
|||||||
<div class="entry-box">
|
<div class="entry-box">
|
||||||
<slot
|
<slot
|
||||||
name="input"
|
name="input"
|
||||||
:spacerText
|
|
||||||
:placeholderText
|
|
||||||
:onUpdateField
|
:onUpdateField
|
||||||
:onFocusField
|
:onFocusField
|
||||||
:onKeydown
|
:onKeydown
|
||||||
>
|
>
|
||||||
<div class="spacer">{{ spacerText }}</div>
|
|
||||||
<div class="placeholder">{{ placeholderText }}</div>
|
|
||||||
<textarea class="field"
|
<textarea class="field"
|
||||||
@input="onUpdateField"
|
@input="onUpdateField"
|
||||||
@focus="onFocusField"
|
@focus="onFocusField"
|
||||||
|
@ -6,6 +6,8 @@ import UserService from '@/services/user'
|
|||||||
import {getAvatarUrl, getDisplayName} from '@/models/user'
|
import {getAvatarUrl, getDisplayName} from '@/models/user'
|
||||||
import {createRandomID} from '@/helpers/randomId'
|
import {createRandomID} from '@/helpers/randomId'
|
||||||
import AutocompleteDropdown from '@/components/input/AutocompleteDropdown.vue'
|
import AutocompleteDropdown from '@/components/input/AutocompleteDropdown.vue'
|
||||||
|
import {useLabelStore} from '@/stores/labels'
|
||||||
|
import XLabel from '@/components/tasks/partials/label.vue'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
modelValue,
|
modelValue,
|
||||||
@ -198,6 +200,12 @@ function updateDateInQuery(newDate: string) {
|
|||||||
filterQuery.value = unEscapeHtml(escaped)
|
filterQuery.value = unEscapeHtml(escaped)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const autocompleteMatchPosition = ref(0)
|
||||||
|
const autocompleteMatchText = ref('')
|
||||||
|
const autocompleteResultType = ref<'labels' | 'assignees' | null>(null)
|
||||||
|
const autocompleteResults = ref<any[]>([])
|
||||||
|
const labelStore = useLabelStore()
|
||||||
|
|
||||||
function handleFieldInput(e, autocompleteOnInput) {
|
function handleFieldInput(e, autocompleteOnInput) {
|
||||||
const cursorPosition = filterInput.value.selectionStart
|
const cursorPosition = filterInput.value.selectionStart
|
||||||
const textUpToCursor = filterQuery.value.substring(0, cursorPosition)
|
const textUpToCursor = filterQuery.value.substring(0, cursorPosition)
|
||||||
@ -209,21 +217,31 @@ function handleFieldInput(e, autocompleteOnInput) {
|
|||||||
if (match !== null) {
|
if (match !== null) {
|
||||||
const [matched, prefix, operator, space, keyword] = match
|
const [matched, prefix, operator, space, keyword] = match
|
||||||
if (keyword) {
|
if (keyword) {
|
||||||
autocompleteResults.value = ['loool', keyword]
|
autocompleteResultType.value = 'labels'
|
||||||
|
autocompleteResults.value = labelStore.filterLabelsByQuery([], keyword)
|
||||||
|
autocompleteMatchText.value = keyword
|
||||||
|
autocompleteMatchPosition.value = prefix.length - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const autocompleteResults = ref<any[]>([])
|
function autocompleteSelect(value) {
|
||||||
|
filterQuery.value = filterQuery.value.substring(0, autocompleteMatchPosition.value + 1) +
|
||||||
|
value.title +
|
||||||
|
filterQuery.value.substring(autocompleteMatchPosition.value + autocompleteMatchText.value.length + 1)
|
||||||
|
|
||||||
|
autocompleteResults.value = []
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">{{ $t('filters.query.title') }}</label>
|
<label class="label">{{ $t('filters.query.title') }}</label>
|
||||||
<AutocompleteDropdown
|
<AutocompleteDropdown
|
||||||
:options="autocompleteResults"
|
:options="autocompleteResults"
|
||||||
@blur="filterInput?.blur()"
|
@blur="filterInput?.blur()"
|
||||||
|
@update:modelValue="autocompleteSelect"
|
||||||
>
|
>
|
||||||
<template
|
<template
|
||||||
v-slot:input="{ onKeydown, onFocusField, onUpdateField }"
|
v-slot:input="{ onKeydown, onFocusField, onUpdateField }"
|
||||||
@ -259,7 +277,11 @@ const autocompleteResults = ref<any[]>([])
|
|||||||
<template
|
<template
|
||||||
v-slot:result="{ item }"
|
v-slot:result="{ item }"
|
||||||
>
|
>
|
||||||
{{ item }}
|
<XLabel
|
||||||
|
v-if="autocompleteResultType === 'labels'"
|
||||||
|
:label="item"
|
||||||
|
/>
|
||||||
|
<template v-else> {{ item }}</template>
|
||||||
</template>
|
</template>
|
||||||
</AutocompleteDropdown>
|
</AutocompleteDropdown>
|
||||||
</div>
|
</div>
|
||||||
@ -324,7 +346,7 @@ const autocompleteResults = ref<any[]>([])
|
|||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
resize: none;
|
resize: none;
|
||||||
|
|
||||||
&.has-autocomplete-results {
|
&.has-autocomplete-results {
|
||||||
border-radius: var(--input-radius) var(--input-radius) 0 0;
|
border-radius: var(--input-radius) var(--input-radius) 0 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user