Skip to content

Commit cc8c9e8

Browse files
authored
feat(home): add double-enter to send top queued message (#4005)
1 parent 606477e commit cc8c9e8

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx

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

3-
import { useLayoutEffect, useRef } from 'react'
3+
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react'
44
import { cn } from '@/lib/core/utils/cn'
55
import { MessageActions } from '@/app/workspace/[workspaceId]/components'
66
import { ChatMessageAttachments } from '@/app/workspace/[workspaceId]/home/components/chat-message-attachments'
@@ -99,6 +99,43 @@ export function MothershipChat({
9999
const hasMessages = messages.length > 0
100100
const initialScrollDoneRef = useRef(false)
101101

102+
const primedQueueIdRef = useRef<string | null>(null)
103+
const primeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
104+
const messageQueueRef = useRef(messageQueue)
105+
messageQueueRef.current = messageQueue
106+
const onSendQueuedMessageRef = useRef(onSendQueuedMessage)
107+
onSendQueuedMessageRef.current = onSendQueuedMessage
108+
109+
const clearPrimed = useCallback(() => {
110+
primedQueueIdRef.current = null
111+
if (primeTimerRef.current) {
112+
clearTimeout(primeTimerRef.current)
113+
primeTimerRef.current = null
114+
}
115+
}, [])
116+
117+
const handleEnterWhileEmpty = useCallback(() => {
118+
const topMessage = messageQueueRef.current[0]
119+
if (!topMessage) return false
120+
121+
if (primedQueueIdRef.current === topMessage.id) {
122+
clearPrimed()
123+
void onSendQueuedMessageRef.current(topMessage.id)
124+
return true
125+
}
126+
127+
primedQueueIdRef.current = topMessage.id
128+
if (primeTimerRef.current) clearTimeout(primeTimerRef.current)
129+
primeTimerRef.current = setTimeout(clearPrimed, 3000)
130+
return true
131+
}, [clearPrimed])
132+
133+
useEffect(() => {
134+
return () => {
135+
if (primeTimerRef.current) clearTimeout(primeTimerRef.current)
136+
}
137+
}, [])
138+
102139
useLayoutEffect(() => {
103140
if (!hasMessages) {
104141
initialScrollDoneRef.current = false
@@ -197,6 +234,8 @@ export function MothershipChat({
197234
onContextAdd={onContextAdd}
198235
editValue={editValue}
199236
onEditValueConsumed={onEditValueConsumed}
237+
onEnterWhileEmpty={handleEnterWhileEmpty}
238+
onPrimedDismiss={clearPrimed}
200239
/>
201240
</div>
202241
</div>

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ interface UserInputProps {
108108
isInitialView?: boolean
109109
userId?: string
110110
onContextAdd?: (context: ChatContext) => void
111+
onEnterWhileEmpty?: () => boolean
112+
onPrimedDismiss?: () => void
111113
}
112114

113115
export function UserInput({
@@ -120,6 +122,8 @@ export function UserInput({
120122
isInitialView = true,
121123
userId,
122124
onContextAdd,
125+
onEnterWhileEmpty,
126+
onPrimedDismiss,
123127
}: UserInputProps) {
124128
const { workspaceId } = useParams<{ workspaceId: string }>()
125129
const { data: workflowsById = {} } = useWorkflowMap(workspaceId)
@@ -208,6 +212,10 @@ export function UserInput({
208212
filesRef.current = files
209213
const contextRef = useRef(contextManagement)
210214
contextRef.current = contextManagement
215+
const onEnterWhileEmptyRef = useRef(onEnterWhileEmpty)
216+
onEnterWhileEmptyRef.current = onEnterWhileEmpty
217+
const isSendingRef = useRef(isSending)
218+
isSendingRef.current = isSending
211219

212220
useEffect(() => {
213221
return () => {
@@ -448,6 +456,9 @@ export function UserInput({
448456
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
449457
if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) {
450458
e.preventDefault()
459+
if (isSendingRef.current && !valueRef.current.trim() && onEnterWhileEmptyRef.current?.()) {
460+
return
461+
}
451462
handleSubmit()
452463
return
453464
}
@@ -540,8 +551,9 @@ export function UserInput({
540551

541552
setValue(newValue)
542553
restartRecognition(newValue)
554+
if (newValue.trim()) onPrimedDismiss?.()
543555
},
544-
[restartRecognition]
556+
[restartRecognition, onPrimedDismiss]
545557
)
546558

547559
const handleSelectAdjust = useCallback(() => {

0 commit comments

Comments
 (0)