diff --git a/frontend/src/components/input/AutocompleteDropdown.vue b/frontend/src/components/input/AutocompleteDropdown.vue
new file mode 100644
index 000000000..096ee09c7
--- /dev/null
+++ b/frontend/src/components/input/AutocompleteDropdown.vue
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+ {{ spacerText }}
+ {{ placeholderText }}
+
+
+
+
+
+
diff --git a/frontend/src/components/project/partials/FilterInput.vue b/frontend/src/components/project/partials/FilterInput.vue
index 667564db4..06b32a684 100644
--- a/frontend/src/components/project/partials/FilterInput.vue
+++ b/frontend/src/components/project/partials/FilterInput.vue
@@ -5,6 +5,7 @@ import DatepickerWithValues from '@/components/date/datepickerWithValues.vue'
import UserService from '@/services/user'
import {getAvatarUrl, getDisplayName} from '@/models/user'
import {createRandomID} from '@/helpers/randomId'
+import AutocompleteDropdown from '@/components/input/AutocompleteDropdown.vue'
const {
modelValue,
@@ -40,14 +41,18 @@ const assigneeFields = [
'assignees',
]
+const labelFields = [
+ 'labels',
+]
+
const availableFilterFields = [
'done',
'priority',
'usePriority',
'percentDone',
- 'labels',
...dateFields,
...assigneeFields,
+ ...labelFields,
]
const filterOperators = [
@@ -69,6 +74,9 @@ const filterJoinOperators = [
')',
]
+const FILTER_OPERATORS_REGEX = '(<|>|<=|>=|=|!=)'
+const FILTER_JOIN_OPERATORS_REGEX = '(&&|\|\||\(|\))'
+
function escapeHtml(unsafe: string): string {
return unsafe
.replace(/&/g, '&')
@@ -91,7 +99,7 @@ const highlightedFilterQuery = computed(() => {
let highlighted = escapeHtml(filterQuery.value)
dateFields
.forEach(o => {
- const pattern = new RegExp(o + '(\\s*)(<|>|<=|>=|=|!=)(\\s*)([\'"]?)([^\'"\\s]+\\1?)?', 'ig')
+ const pattern = new RegExp(o + '(\\s*)' + FILTER_OPERATORS_REGEX + '(\\s*)([\'"]?)([^\'"\\s]+\\1?)?', 'ig')
highlighted = highlighted.replaceAll(pattern, (match, spacesBefore, token, spacesAfter, start, value, position) => {
if (typeof value === 'undefined') {
value = ''
@@ -102,7 +110,7 @@ const highlightedFilterQuery = computed(() => {
})
assigneeFields
.forEach(f => {
- const pattern = new RegExp(f + '\\s*(<|>|<=|>=|=|!=)\\s*([\'"]?)([^\'"\\s]+\\1?)?', 'ig')
+ const pattern = new RegExp(f + '\\s*' + FILTER_OPERATORS_REGEX + '\\s*([\'"]?)([^\'"\\s]+\\1?)?', 'ig')
highlighted = highlighted.replaceAll(pattern, (match, token, start, value) => {
if (typeof value === 'undefined') {
value = ''
@@ -189,33 +197,70 @@ function updateDateInQuery(newDate: string) {
currentOldDatepickerValue.value = newDate
filterQuery.value = unEscapeHtml(escaped)
}
+
+function handleFieldInput(e, autocompleteOnInput) {
+ const cursorPosition = filterInput.value.selectionStart
+ const textUpToCursor = filterQuery.value.substring(0, cursorPosition)
+
+ labelFields.forEach(l => {
+ const pattern = new RegExp('(' + l + '\\s*' + FILTER_OPERATORS_REGEX + '\\s*)([\'"]?)([^\'"&\|\(\)]+\\1?)?$', 'ig')
+ const match = pattern.exec(textUpToCursor)
+
+ if (match !== null) {
+ const [matched, prefix, operator, space, keyword] = match
+ if (keyword) {
+ autocompleteResults.value = ['loool', keyword]
+ }
+ }
+ })
+}
+
+const autocompleteResults = ref([])
-
+
+
+
+
+
+ whoo {{ item }}
+
+