diff --git a/ui/desktop/src/components/MentionPopover.tsx b/ui/desktop/src/components/MentionPopover.tsx index 07c674e7..0ca65ba1 100644 --- a/ui/desktop/src/components/MentionPopover.tsx +++ b/ui/desktop/src/components/MentionPopover.tsx @@ -17,6 +17,10 @@ const i18n = defineMessages({ id: 'mentionPopover.scanningFiles', defaultMessage: 'Scanning files...', }, + loadingCommands: { + id: 'mentionPopover.loadingCommands', + defaultMessage: 'Loading commands...', + }, itemsFound: { id: 'mentionPopover.itemsFound', defaultMessage: '{count, plural, one {# item} other {# items}} found', @@ -25,6 +29,10 @@ const i18n = defineMessages({ id: 'mentionPopover.noItemsFound', defaultMessage: 'No items found matching "{query}"', }, + noCommandsFound: { + id: 'mentionPopover.noCommandsFound', + defaultMessage: 'No commands found matching "{query}"', + }, }); type DisplayItemType = CommandType | 'Directory' | 'File'; @@ -374,30 +382,11 @@ const MentionPopover = forwardRef< [] ); - const scanFilesFromRoot = useCallback(async () => { - setIsLoading(true); - try { - let startPath = currentWorkingDir; - - if (!startPath) { - if (window.electron.platform === 'win32') { - startPath = 'C:\\Users'; - } else if (window.electron.platform === 'linux') { - startPath = '/home'; - } else { - startPath = '/Users'; // Default to macOS - } - } - - const scannedFiles = await scanDirectoryFromRoot(startPath); - setItems(scannedFiles); - } catch (error) { - console.error('Error scanning items from root:', error); - setItems([]); - } finally { - setIsLoading(false); - } - }, [scanDirectoryFromRoot, currentWorkingDir]); + const getDefaultStartPath = (): string => { + if (window.electron.platform === 'win32') return 'C:\\Users'; + if (window.electron.platform === 'linux') return '/home'; + return '/Users'; + }; const compareByType = (a: DisplayItemWithMatch, b: DisplayItemWithMatch) => { const orderA = typeOrder[a.itemType] ?? Number.MAX_SAFE_INTEGER; @@ -485,28 +474,50 @@ const MentionPopover = forwardRef< ); useEffect(() => { + let cancelled = false; + const loadData = async () => { - if (isSlashCommand) { - const response = await getSlashCommands({ - query: { working_dir: currentWorkingDir }, - throwOnError: true, - }); - const commandItems: DisplayItem[] = (response.data?.commands || []).map((cmd) => ({ - name: cmd.command, - extra: cmd.help, - itemType: cmd.command_type, - relativePath: cmd.command, - })); - setItems(commandItems); - } else { - await scanFilesFromRoot(); + setItems([]); + setIsLoading(true); + try { + if (isSlashCommand) { + const response = await getSlashCommands({ + query: { working_dir: currentWorkingDir }, + throwOnError: true, + }); + if (cancelled) return; + const commandItems: DisplayItem[] = (response.data?.commands || []).map((cmd) => ({ + name: cmd.command, + extra: cmd.help, + itemType: cmd.command_type, + relativePath: cmd.command, + })); + setItems(commandItems); + } else { + const scannedFiles = await scanDirectoryFromRoot(currentWorkingDir || getDefaultStartPath()); + if (cancelled) return; + setItems(scannedFiles); + } + } catch (error) { + if (!cancelled) { + console.error('Error loading popover items:', error); + setItems([]); + } + } finally { + if (!cancelled) { + setIsLoading(false); + } } }; if (isOpen) { loadData(); } - }, [isOpen, isSlashCommand, scanFilesFromRoot, currentWorkingDir]); + + return () => { + cancelled = true; + }; + }, [isOpen, isSlashCommand, scanDirectoryFromRoot, currentWorkingDir]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -561,7 +572,7 @@ const MentionPopover = forwardRef< {isLoading ? (