fix(inbox): Fix tag/project autocomplete selection (#1043)
* fix(mcp): Include subtasks in get_task API response Add Subtasks association to the findTaskByIdentifier function so that the get_task MCP API endpoint returns subtasks along with the main task. This enables clients to access the full task hierarchy in a single API call. The serializeTask function already supported subtasks serialization, so this change only required updating the query includes to load the Subtasks relation with proper ordering and Tag associations. Fixes #1029 * fix(inbox): Fix tag/project autocomplete selection Fixes #996 Previously, when creating a task from inbox with autocomplete suggestions, the tag/project replacement would fail if there was regular text before the hashtag or plus sign. This caused two issues: 1. When typing "#technical_writing" and creating a task, the tag wouldn't be created or applied because the autocomplete wasn't replacing the input 2. When typing "#tech_" and selecting "technical_writing" from autocomplete, a new tag "tech_" would be created instead of applying the existing tag This was caused by an overly restrictive condition in handleTagSelect and handleProjectSelect that prevented replacement when there was regular text before the tag/project marker. Changes: - Removed the allowReplacement condition that blocked autocomplete when regular text preceded the tag/project marker - Simplified handleTagSelect and handleProjectSelect to always replace partial input when a suggestion is selected - Added a space after the selected tag/project for better UX
This commit is contained in:
parent
0440f46645
commit
dcb711c515
1 changed files with 45 additions and 93 deletions
|
|
@ -910,53 +910,29 @@ const QuickCaptureInput = React.forwardRef<
|
||||||
const hashtagMatch = beforeCursor.match(/#([a-zA-Z0-9_]*)$/);
|
const hashtagMatch = beforeCursor.match(/#([a-zA-Z0-9_]*)$/);
|
||||||
|
|
||||||
if (hashtagMatch) {
|
if (hashtagMatch) {
|
||||||
const hashtagStart = beforeCursor.lastIndexOf('#');
|
const newText =
|
||||||
const textBeforeHashtag = inputText
|
beforeCursor.replace(
|
||||||
.substring(0, hashtagStart)
|
/#([a-zA-Z0-9_]*)$/,
|
||||||
.trim();
|
`#${tagName} `
|
||||||
const textAfterCursor = afterCursor.trim();
|
) + afterCursor;
|
||||||
|
setInputText(newText);
|
||||||
|
setShowTagSuggestions(false);
|
||||||
|
setFilteredTags([]);
|
||||||
|
setSelectedSuggestionIndex(-1);
|
||||||
|
|
||||||
let allowReplacement = false;
|
setTimeout(() => {
|
||||||
|
if (inputRef.current) {
|
||||||
if (textAfterCursor === '' || textBeforeHashtag === '') {
|
inputRef.current.focus();
|
||||||
allowReplacement = true;
|
const newCursorPos = beforeCursor.replace(
|
||||||
} else {
|
|
||||||
const wordsBeforeHashtag = textBeforeHashtag
|
|
||||||
.split(/\s+/)
|
|
||||||
.filter((word) => word.length > 0);
|
|
||||||
const allWordsAreTagsOrProjects = wordsBeforeHashtag.every(
|
|
||||||
(word) => word.startsWith('#') || word.startsWith('+')
|
|
||||||
);
|
|
||||||
if (allWordsAreTagsOrProjects) {
|
|
||||||
allowReplacement = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowReplacement) {
|
|
||||||
const newText =
|
|
||||||
beforeCursor.replace(
|
|
||||||
/#([a-zA-Z0-9_]*)$/,
|
/#([a-zA-Z0-9_]*)$/,
|
||||||
`#${tagName}`
|
`#${tagName} `
|
||||||
) + afterCursor;
|
).length;
|
||||||
setInputText(newText);
|
inputRef.current.setSelectionRange(
|
||||||
setShowTagSuggestions(false);
|
newCursorPos,
|
||||||
setFilteredTags([]);
|
newCursorPos
|
||||||
setSelectedSuggestionIndex(-1);
|
);
|
||||||
|
}
|
||||||
setTimeout(() => {
|
}, 0);
|
||||||
if (inputRef.current) {
|
|
||||||
inputRef.current.focus();
|
|
||||||
const newCursorPos = beforeCursor.replace(
|
|
||||||
/#([a-zA-Z0-9_]*)$/,
|
|
||||||
`#${tagName}`
|
|
||||||
).length;
|
|
||||||
inputRef.current.setSelectionRange(
|
|
||||||
newCursorPos,
|
|
||||||
newCursorPos
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -968,57 +944,33 @@ const QuickCaptureInput = React.forwardRef<
|
||||||
);
|
);
|
||||||
|
|
||||||
if (projectMatch) {
|
if (projectMatch) {
|
||||||
const projectStart = beforeCursor.lastIndexOf('+');
|
const formattedProjectName = projectName.includes(' ')
|
||||||
const textBeforeProject = inputText
|
? `"${projectName}"`
|
||||||
.substring(0, projectStart)
|
: projectName;
|
||||||
.trim();
|
|
||||||
const textAfterCursor = afterCursor.trim();
|
|
||||||
|
|
||||||
let allowReplacement = false;
|
const newText =
|
||||||
|
beforeCursor.replace(
|
||||||
|
/\+(?:"([^"]*)"|([a-zA-Z0-9_\s]*))$/,
|
||||||
|
`+${formattedProjectName} `
|
||||||
|
) + afterCursor;
|
||||||
|
setInputText(newText);
|
||||||
|
setShowProjectSuggestions(false);
|
||||||
|
setFilteredProjects([]);
|
||||||
|
setSelectedSuggestionIndex(-1);
|
||||||
|
|
||||||
if (textAfterCursor === '' || textBeforeProject === '') {
|
setTimeout(() => {
|
||||||
allowReplacement = true;
|
if (inputRef.current) {
|
||||||
} else {
|
inputRef.current.focus();
|
||||||
const wordsBeforeProject = textBeforeProject
|
const newCursorPos = beforeCursor.replace(
|
||||||
.split(/\s+/)
|
|
||||||
.filter((word) => word.length > 0);
|
|
||||||
const allWordsAreTagsOrProjects = wordsBeforeProject.every(
|
|
||||||
(word) => word.startsWith('#') || word.startsWith('+')
|
|
||||||
);
|
|
||||||
if (allWordsAreTagsOrProjects) {
|
|
||||||
allowReplacement = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowReplacement) {
|
|
||||||
const formattedProjectName = projectName.includes(' ')
|
|
||||||
? `"${projectName}"`
|
|
||||||
: projectName;
|
|
||||||
|
|
||||||
const newText =
|
|
||||||
beforeCursor.replace(
|
|
||||||
/\+(?:"([^"]*)"|([a-zA-Z0-9_\s]*))$/,
|
/\+(?:"([^"]*)"|([a-zA-Z0-9_\s]*))$/,
|
||||||
`+${formattedProjectName}`
|
`+${formattedProjectName} `
|
||||||
) + afterCursor;
|
).length;
|
||||||
setInputText(newText);
|
inputRef.current.setSelectionRange(
|
||||||
setShowProjectSuggestions(false);
|
newCursorPos,
|
||||||
setFilteredProjects([]);
|
newCursorPos
|
||||||
setSelectedSuggestionIndex(-1);
|
);
|
||||||
|
}
|
||||||
setTimeout(() => {
|
}, 0);
|
||||||
if (inputRef.current) {
|
|
||||||
inputRef.current.focus();
|
|
||||||
const newCursorPos = beforeCursor.replace(
|
|
||||||
/\+(?:"([^"]*)"|([a-zA-Z0-9_\s]*))$/,
|
|
||||||
`+${formattedProjectName}`
|
|
||||||
).length;
|
|
||||||
inputRef.current.setSelectionRange(
|
|
||||||
newCursorPos,
|
|
||||||
newCursorPos
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue