mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-04-28 18:38:24 -05:00
fix(components): fix all type errors in FilterAutocomplete.ts
- Add type filters for label and project arrays to remove undefined values - Add @ts-expect-error for projectId parameter in getAll call - Add type assertion for userService.getAll empty object parameter - Add default value for prefix in destructuring - Add null check for match.index - Add type assertions for union type property access (username/title) - Add null check for autocompleteContext - Fix Selection.near call with @ts-expect-error comment - Add optional chaining for array access that could be undefined
This commit is contained in:
@@ -167,7 +167,7 @@ export default Extension.create<FilterAutocompleteOptions>({
|
||||
const fetchSuggestions = async (autocompleteContext: AutocompleteContext, fieldType: AutocompleteField): Promise<SuggestionItem[]> => {
|
||||
try {
|
||||
if (fieldType === 'labels') {
|
||||
return labelStore.filterLabelsByQuery([], autocompleteContext.search)
|
||||
return labelStore.filterLabelsByQuery([], autocompleteContext.search).filter((label): label is ILabel => label !== undefined) as SuggestionItem[]
|
||||
}
|
||||
|
||||
if (fieldType === 'assignees') {
|
||||
@@ -181,9 +181,10 @@ export default Extension.create<FilterAutocompleteOptions>({
|
||||
let assigneeSuggestions: SuggestionItem[] = []
|
||||
try {
|
||||
if (this.options.projectId) {
|
||||
assigneeSuggestions = await projectUserService.getAll({projectId: this.options.projectId}, {s: autocompleteContext.search})
|
||||
// @ts-expect-error - projectId is used for URL replacement but not part of IAbstract
|
||||
assigneeSuggestions = await projectUserService.getAll({projectId: this.options.projectId}, {s: autocompleteContext.search}) as SuggestionItem[]
|
||||
} else {
|
||||
assigneeSuggestions = await userService.getAll({}, {s: autocompleteContext.search})
|
||||
assigneeSuggestions = await userService.getAll({} as IUser, {s: autocompleteContext.search}) as SuggestionItem[]
|
||||
}
|
||||
// For assignees, show suggestions even with empty search, but limit if we have many
|
||||
if (autocompleteContext.search === '' && assigneeSuggestions.length > 10) {
|
||||
@@ -197,9 +198,9 @@ export default Extension.create<FilterAutocompleteOptions>({
|
||||
}, 300)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if (fieldType === 'projects' && !this.options.projectId) {
|
||||
return projectStore.searchProject(autocompleteContext.search)
|
||||
return projectStore.searchProject(autocompleteContext.search).filter((project): project is IProject => project !== undefined) as SuggestionItem[]
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching suggestions:', error)
|
||||
@@ -257,14 +258,14 @@ export default Extension.create<FilterAutocompleteOptions>({
|
||||
const pattern = new RegExp(`(${field}\\s*${FILTER_OPERATORS_REGEX}\\s*)(["']?)([^"'&|()]*)?$`, 'ig')
|
||||
const match = pattern.exec(textUpToCursor)
|
||||
|
||||
if (match) {
|
||||
const [, prefix, , , keyword = ''] = match
|
||||
if (match && match.index !== undefined) {
|
||||
const [, prefix = '', , , keyword = ''] = match
|
||||
|
||||
let search = keyword.trim()
|
||||
const operator = match[0].match(new RegExp(FILTER_OPERATORS_REGEX))?.[0] || ''
|
||||
if (operator === 'in' || operator === '?=') {
|
||||
const keywords = keyword.split(',')
|
||||
search = keywords[keywords.length - 1].trim()
|
||||
search = keywords[keywords.length - 1]?.trim() ?? ''
|
||||
}
|
||||
|
||||
// Check if this expression is complete
|
||||
@@ -327,23 +328,28 @@ export default Extension.create<FilterAutocompleteOptions>({
|
||||
items,
|
||||
command: (item: AutocompleteItem) => {
|
||||
// Handle selection
|
||||
const newValue = item.fieldType === 'assignees' ? item.item.username : item.item.title
|
||||
const newValue = item.fieldType === 'assignees'
|
||||
? (item.item as IUser).username
|
||||
: (item.item as IProject | ILabel).title
|
||||
const {from} = view.state.selection
|
||||
const context = autocompleteContext
|
||||
if (!context) {
|
||||
return
|
||||
}
|
||||
const operator = context.operator
|
||||
|
||||
|
||||
let insertValue: string = newValue ?? ''
|
||||
const replaceFrom = Math.max(0, from - context.search.length)
|
||||
const replaceTo = from
|
||||
|
||||
|
||||
// Handle multi-value operators
|
||||
if (isMultiValueOperator(operator) && context.keyword.includes(',')) {
|
||||
// For multi-value fields, we need to replace only the current search term
|
||||
const keywords = context.keyword.split(',')
|
||||
const currentKeywordIndex = keywords.length - 1
|
||||
|
||||
|
||||
// If we're not adding the first item, add comma prefix
|
||||
if (currentKeywordIndex > 0 && keywords[currentKeywordIndex].trim() === context.search.trim()) {
|
||||
if (currentKeywordIndex > 0 && keywords[currentKeywordIndex]?.trim() === context.search.trim()) {
|
||||
// We're replacing the last incomplete keyword
|
||||
insertValue = newValue ?? ''
|
||||
} else {
|
||||
@@ -351,7 +357,7 @@ export default Extension.create<FilterAutocompleteOptions>({
|
||||
insertValue = ',' + newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const tr = view.state.tr.replaceWith(
|
||||
replaceFrom,
|
||||
replaceTo,
|
||||
@@ -359,6 +365,7 @@ export default Extension.create<FilterAutocompleteOptions>({
|
||||
)
|
||||
// Position cursor after the inserted text
|
||||
const newPos = replaceFrom + insertValue.length
|
||||
// @ts-expect-error - Selection.near is a static method but TypeScript doesn't recognize it on constructor
|
||||
tr.setSelection(view.state.selection.constructor.near(tr.doc.resolve(newPos)))
|
||||
view.dispatch(tr)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user