mirror of
https://github.com/go-vikunja/vikunja.git
synced 2025-12-05 19:16:51 -06:00
fix(filters): support project filter in parentheses (#1647)
The filter regex pattern was not matching values inside parentheses correctly. The lookahead pattern only allowed `&&`, `||`, or end-of-string after filter values, but when filters are wrapped in parentheses like `( project = Filtertest )`, the closing `)` appears after the value. Fixed by adding `\)` to the lookahead pattern so it correctly handles closing parentheses. This allows the project filter (and other filters) to work properly when nested in parentheses. - Added tests for project filters in parentheses (both frontend and backend) - Backend tests confirm the backend already handled this correctly - Frontend regex pattern now matches the backend behavior Fixes #1645
This commit is contained in:
@@ -187,6 +187,26 @@ describe('Filter Transformation', () => {
|
||||
|
||||
expect(transformed).toBe('project = 1')
|
||||
})
|
||||
|
||||
it('should correctly resolve project in parentheses', () => {
|
||||
const transformed = transformFilterStringForApi(
|
||||
'( project = Filtertest )',
|
||||
nullTitleToIdResolver,
|
||||
(title: string) => title === 'Filtertest' ? 123 : null,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('( project = 123 )')
|
||||
})
|
||||
|
||||
it('should correctly resolve project with OR in parentheses', () => {
|
||||
const transformed = transformFilterStringForApi(
|
||||
'( labels = label || project = Filtertest )',
|
||||
(title: string) => title === 'label' ? 456 : null,
|
||||
(title: string) => title === 'Filtertest' ? 123 : null,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('( labels = 456 || project = 123 )')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Special Characters', () => {
|
||||
|
||||
@@ -81,7 +81,7 @@ export function hasFilterQuery(filter: string): boolean {
|
||||
}
|
||||
|
||||
export function getFilterFieldRegexPattern(field: string): RegExp {
|
||||
return new RegExp('\\b(' + field + ')\\s*' + FILTER_OPERATORS_REGEX + '\\s*(?:(["\'])((?:\\\\.|(?!\\3)[^\\\\])*?)\\3|([^&|()<]+?))(?=\\s*(?:&&|\\||$))', 'g')
|
||||
return new RegExp('\\b(' + field + ')\\s*' + FILTER_OPERATORS_REGEX + '\\s*(?:(["\'])((?:\\\\.|(?!\\3)[^\\\\])*?)\\3|([^&|()<]+?))(?=\\s*(?:&&|\\||\\)|$))', 'g')
|
||||
}
|
||||
|
||||
export function transformFilterStringForApi(
|
||||
|
||||
@@ -284,4 +284,31 @@ func TestParseFilter(t *testing.T) {
|
||||
assert.Equal(t, 0, date.Year())
|
||||
}
|
||||
})
|
||||
t.Run("project with parentheses", func(t *testing.T) {
|
||||
result, err := getTaskFiltersFromFilterString("( project = 1 )", "UTC")
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result, 1)
|
||||
require.Len(t, result[0].value, 1)
|
||||
|
||||
firstSet := result[0].value.([]*taskFilter)
|
||||
assert.Equal(t, "project_id", firstSet[0].field)
|
||||
assert.Equal(t, taskFilterComparatorEquals, firstSet[0].comparator)
|
||||
assert.Equal(t, int64(1), firstSet[0].value)
|
||||
})
|
||||
t.Run("project with OR in parentheses", func(t *testing.T) {
|
||||
result, err := getTaskFiltersFromFilterString("( done = false || project = 1 )", "UTC")
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result, 1)
|
||||
require.Len(t, result[0].value, 2)
|
||||
|
||||
firstSet := result[0].value.([]*taskFilter)
|
||||
assert.Equal(t, "done", firstSet[0].field)
|
||||
assert.Equal(t, taskFilterComparatorEquals, firstSet[0].comparator)
|
||||
assert.Equal(t, false, firstSet[0].value)
|
||||
assert.Equal(t, "project_id", firstSet[1].field)
|
||||
assert.Equal(t, taskFilterComparatorEquals, firstSet[1].comparator)
|
||||
assert.Equal(t, int64(1), firstSet[1].value)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user