fix(filters): handle multiple projects correctly in parsing, fixing autocomplete

Resolves https://github.com/go-vikunja/vikunja/issues/1395
This commit is contained in:
kolaente 2025-11-16 15:53:40 +01:00
parent 675a550247
commit 067cc5674b
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
1 changed files with 61 additions and 2 deletions

View File

@ -8,6 +8,7 @@ import {
FILTER_OPERATORS_REGEX,
getFilterFieldRegexPattern,
LABEL_FIELDS,
PROJECT_FIELDS,
} from '@/helpers/filters'
import {useLabelStore} from '@/stores/labels'
import {colorIsDark} from '@/helpers/color/colorIsDark.ts'
@ -148,12 +149,70 @@ function decorateDocument(doc: Node) {
}
})
// Match other values - anything coming after an operator (excluding labels and dates)
// Handle project fields with multi-value support
PROJECT_FIELDS.forEach(projectField => {
const pattern = getFilterFieldRegexPattern(projectField)
let projectMatch
while ((projectMatch = pattern.exec(text)) !== null) {
const projectValue = projectMatch[4]?.trim()
const operator = projectMatch[2]?.trim()
if(!projectValue) {
continue
}
const valueStart = projectMatch.index + projectMatch[0].lastIndexOf(projectValue)
const valueEnd = valueStart + projectValue.length
const addProjectDecoration = (projectValue: string, start: number, end: number) => {
const from = findPosForIndex(doc, start)
const to = findPosForIndex(doc, end)
if (from === null || to === null) {
return
}
valueRanges.push({start, end})
// Use generic value styling for projects
decorations.push(
Decoration.inline(from, to, {class: 'value'}),
)
}
// Check if this is a multi-value operator and the value contains commas
const isMultiValueOperator = ['in', '?=', 'not in', '?!='].includes(operator)
if (isMultiValueOperator && projectValue.includes(',')) {
// Split by commas and create decorations for each individual project
const projects = projectValue.split(',').map(p => p.trim()).filter(p => p.length > 0)
let currentOffset = 0
projects.forEach(individualProject => {
// Find the position of this individual project within the full value
const projectIndex = projectValue.indexOf(individualProject, currentOffset)
if (projectIndex !== -1) {
const individualStart = valueStart + projectIndex
const individualEnd = individualStart + individualProject.length
addProjectDecoration(individualProject, individualStart, individualEnd)
currentOffset = projectIndex + individualProject.length
}
})
continue
}
addProjectDecoration(projectValue, valueStart, valueEnd)
}
})
// Match other values - anything coming after an operator (excluding labels, dates, and projects)
fieldValueRegex.lastIndex = 0
while ((match = fieldValueRegex.exec(text)) !== null) {
const [fullMatch, field, operator, value] = match
if (LABEL_FIELDS.includes(field) || DATE_FIELDS.includes(field)) {
if (LABEL_FIELDS.includes(field) || DATE_FIELDS.includes(field) || PROJECT_FIELDS.includes(field)) {
continue
}