Skip to content

Commit 8f224ce

Browse files
committed
fix(chat): warm resource lists on editor focus so fast mentions resolve
Deferring the lists to menu-open left a window where `selectActive()` saw an empty candidate list, and its `false` return falls through to submitting the message with the mention unresolved. Start hydrating on first focus — the earliest reliable signal a mention may be coming — which closes the window while keeping the lists off the page-load path.
1 parent d66b103 commit 8f224ce

2 files changed

Lines changed: 20 additions & 4 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ const MENTION_ONLY_RESOURCE_TYPES = new Set<MothershipResourceType>(['integratio
4141

4242
interface PlusMenuDropdownProps {
4343
workspaceId: string
44+
/**
45+
* Starts hydrating the resource lists before the menu opens. The editor sets
46+
* this on focus: `@`-mention confirmation reads the candidate list
47+
* synchronously on Enter, and an empty list falls through to submitting the
48+
* message with the mention unresolved. Focus is the earliest reliable signal
49+
* that a mention may be coming, and still keeps these lists off page load.
50+
*/
51+
warm?: boolean
4452
onResourceSelect: (resource: MothershipResource) => void
4553
onClose: () => void
4654
textareaRef: React.RefObject<HTMLTextAreaElement | null>
@@ -51,7 +59,7 @@ interface PlusMenuDropdownProps {
5159

5260
export const PlusMenuDropdown = React.memo(
5361
React.forwardRef<PlusMenuHandle, PlusMenuDropdownProps>(function PlusMenuDropdown(
54-
{ workspaceId, onResourceSelect, onClose, textareaRef, pendingCursorRef, mentionQuery },
62+
{ workspaceId, warm, onResourceSelect, onClose, textareaRef, pendingCursorRef, mentionQuery },
5563
ref
5664
) {
5765
const [open, setOpen] = useState(false)
@@ -62,8 +70,8 @@ export const PlusMenuDropdown = React.memo(
6270
const searchRef = useRef<HTMLInputElement>(null)
6371
const contentRef = useRef<HTMLDivElement>(null)
6472

65-
// Gated on `open` so an idle chat surface never fetches the workspace lists.
66-
const availableResources = useAvailableResources(workspaceId, { enabled: open })
73+
// Gated so an idle chat surface never fetches the workspace lists.
74+
const availableResources = useAvailableResources(workspaceId, { enabled: open || !!warm })
6775

6876
const doOpen = useCallback(
6977
(anchor: { left: number; top: number }, options?: { mention?: boolean }) => {

apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react'
3+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
44
import { cn } from '@sim/emcn'
55
import { ContextMentionIcon } from '@/app/workspace/[workspaceId]/home/components/context-mention-icon'
66
import {
@@ -72,6 +72,12 @@ export function PromptEditor({
7272
}: PromptEditorProps) {
7373
const { textareaRef, value } = editor
7474
const scrollerRef = useRef<HTMLDivElement>(null)
75+
/**
76+
* Latched on first focus and never cleared: it only starts the resource
77+
* lists early so an `@`-mention has candidates by the time Enter is pressed.
78+
* Un-warming on blur would just re-open the race on the next focus.
79+
*/
80+
const [hasFocused, setHasFocused] = useState(false)
7581

7682
/**
7783
* Autosize: grow the textarea to its full content height; the scroller caps
@@ -203,6 +209,7 @@ export function PromptEditor({
203209
onKeyDown={
204210
readOnly ? undefined : (e) => editor.handleKeyDown(e, { onSubmit, onArrowUpOnEmpty })
205211
}
212+
onFocus={readOnly ? undefined : () => setHasFocused(true)}
206213
onPaste={readOnly ? undefined : editor.handlePaste}
207214
onCopy={editor.handleCopy}
208215
onCut={readOnly ? undefined : editor.handleCut}
@@ -220,6 +227,7 @@ export function PromptEditor({
220227
<PlusMenuDropdown
221228
ref={editor.plusMenuRef}
222229
workspaceId={editor.workspaceId}
230+
warm={hasFocused}
223231
onResourceSelect={editor.insertResource}
224232
onClose={editor.handlePlusMenuClose}
225233
textareaRef={editor.textareaRef}

0 commit comments

Comments
 (0)