Skip to content

Commit c0ff3ca

Browse files
committed
fix ui
1 parent 4131fe2 commit c0ff3ca

File tree

6 files changed

+80
-53
lines changed

6 files changed

+80
-53
lines changed
Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
'use client'
22

3-
import { useCallback, useState } from 'react'
3+
import { useCallback, useEffect, useRef, useState } from 'react'
44
import { Check, Copy, Ellipsis, Hash } from 'lucide-react'
55
import {
6-
Popover,
7-
PopoverContent,
8-
PopoverItem,
9-
PopoverScrollArea,
10-
PopoverTrigger,
6+
DropdownMenu,
7+
DropdownMenuContent,
8+
DropdownMenuItem,
9+
DropdownMenuTrigger,
10+
Tooltip,
1111
} from '@/components/emcn'
1212

1313
interface MessageActionsProps {
@@ -16,60 +16,75 @@ interface MessageActionsProps {
1616
}
1717

1818
export function MessageActions({ content, requestId }: MessageActionsProps) {
19-
const [open, setOpen] = useState(false)
2019
const [copied, setCopied] = useState<'message' | 'request' | null>(null)
20+
const resetTimeoutRef = useRef<number | null>(null)
21+
22+
useEffect(() => {
23+
return () => {
24+
if (resetTimeoutRef.current !== null) {
25+
window.clearTimeout(resetTimeoutRef.current)
26+
}
27+
}
28+
}, [])
2129

2230
const copyToClipboard = useCallback(async (text: string, type: 'message' | 'request') => {
2331
try {
2432
await navigator.clipboard.writeText(text)
2533
setCopied(type)
26-
setTimeout(() => setCopied(null), 1500)
34+
if (resetTimeoutRef.current !== null) {
35+
window.clearTimeout(resetTimeoutRef.current)
36+
}
37+
resetTimeoutRef.current = window.setTimeout(() => setCopied(null), 1500)
2738
} catch {
28-
// Silently fail
39+
return
2940
}
30-
setOpen(false)
3141
}, [])
3242

43+
if (!content && !requestId) {
44+
return null
45+
}
46+
3347
return (
34-
<Popover variant='default' size='sm' open={open} onOpenChange={setOpen}>
35-
<PopoverTrigger asChild>
36-
<button
37-
type='button'
38-
className='rounded-md p-1 text-[var(--text-icon)] opacity-0 transition-opacity hover:bg-[var(--surface-3)] group-hover/msg:opacity-100 data-[state=open]:opacity-100'
39-
onClick={(e) => e.stopPropagation()}
48+
<DropdownMenu modal={false}>
49+
<Tooltip.Root>
50+
<Tooltip.Trigger asChild>
51+
<DropdownMenuTrigger asChild>
52+
<button
53+
type='button'
54+
aria-label='More options'
55+
className='flex h-5 w-5 items-center justify-center rounded-sm text-[var(--text-icon)] opacity-0 transition-colors transition-opacity hover:bg-[var(--surface-3)] hover:text-[var(--text-primary)] focus-visible:opacity-100 focus-visible:outline-none group-hover/msg:opacity-100 data-[state=open]:opacity-100'
56+
onClick={(event) => event.stopPropagation()}
57+
>
58+
<Ellipsis className='h-3 w-3' strokeWidth={2} />
59+
</button>
60+
</DropdownMenuTrigger>
61+
</Tooltip.Trigger>
62+
<Tooltip.Content side='top'>More options</Tooltip.Content>
63+
</Tooltip.Root>
64+
<DropdownMenuContent align='end' side='top' sideOffset={4}>
65+
<DropdownMenuItem
66+
disabled={!content}
67+
onSelect={(event) => {
68+
event.stopPropagation()
69+
void copyToClipboard(content, 'message')
70+
}}
71+
>
72+
{copied === 'message' ? <Check /> : <Copy />}
73+
<span>Copy Message</span>
74+
</DropdownMenuItem>
75+
<DropdownMenuItem
76+
disabled={!requestId}
77+
onSelect={(event) => {
78+
event.stopPropagation()
79+
if (requestId) {
80+
void copyToClipboard(requestId, 'request')
81+
}
82+
}}
4083
>
41-
<Ellipsis className='h-[14px] w-[14px]' strokeWidth={2} />
42-
</button>
43-
</PopoverTrigger>
44-
<PopoverContent
45-
side='bottom'
46-
align='end'
47-
sideOffset={4}
48-
maxHeight={120}
49-
style={{ width: '160px', minWidth: '160px' }}
50-
>
51-
<PopoverScrollArea>
52-
<PopoverItem onClick={() => copyToClipboard(content, 'message')} disabled={!content}>
53-
{copied === 'message' ? (
54-
<Check className='h-[13px] w-[13px]' />
55-
) : (
56-
<Copy className='h-[13px] w-[13px]' />
57-
)}
58-
<span>Copy Message</span>
59-
</PopoverItem>
60-
<PopoverItem
61-
onClick={() => requestId && copyToClipboard(requestId, 'request')}
62-
disabled={!requestId}
63-
>
64-
{copied === 'request' ? (
65-
<Check className='h-[13px] w-[13px]' />
66-
) : (
67-
<Hash className='h-[13px] w-[13px]' />
68-
)}
69-
<span>Copy Request ID</span>
70-
</PopoverItem>
71-
</PopoverScrollArea>
72-
</PopoverContent>
73-
</Popover>
84+
{copied === 'request' ? <Check /> : <Hash />}
85+
<span>Copy Request ID</span>
86+
</DropdownMenuItem>
87+
</DropdownMenuContent>
88+
</DropdownMenu>
7489
)
7590
}

apps/sim/app/workspace/[workspaceId]/home/home.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,9 @@ export function Home({ chatId }: HomeProps = {}) {
415415
const isLastMessage = index === messages.length - 1
416416

417417
return (
418-
<div key={msg.id} className='group/msg relative pb-4'>
418+
<div key={msg.id} className='group/msg relative pb-5'>
419419
{!isThisStreaming && (msg.content || msg.contentBlocks?.length) && (
420-
<div className='-top-1 absolute right-0 z-10'>
420+
<div className='absolute right-0 bottom-0 z-10'>
421421
<MessageActions content={msg.content} requestId={msg.requestId} />
422422
</div>
423423
)}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,11 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
414414
style={{ '--panel-max-width': `${panelWidth - 16}px` } as React.CSSProperties}
415415
>
416416
{!isStreaming && message.content && (
417-
<div className='-top-1 absolute right-0 z-10'>
417+
<div className='absolute right-0 bottom-0 z-10'>
418418
<MessageActions content={message.content} requestId={message.requestId} />
419419
</div>
420420
)}
421-
<div className='max-w-full space-y-[4px] px-[2px] pb-[4px]'>
421+
<div className='max-w-full space-y-[4px] px-[2px] pb-5'>
422422
{/* Content blocks in chronological order */}
423423
{memoizedContentBlocks || (isStreaming && <div className='min-h-0' />)}
424424

apps/sim/lib/copilot/client-sse/handlers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export function flushStreamingUpdates(set: StoreSet) {
9292
if (update) {
9393
return {
9494
...msg,
95+
requestId: update.requestId ?? msg.requestId,
9596
content: '',
9697
contentBlocks:
9798
update.contentBlocks.length > 0
@@ -129,6 +130,7 @@ export function updateStreamingMessage(set: StoreSet, context: ClientStreamingCo
129130
const newMessages = [...messages]
130131
newMessages[messages.length - 1] = {
131132
...lastMessage,
133+
requestId: lastMessageUpdate.requestId ?? lastMessage.requestId,
132134
content: '',
133135
contentBlocks:
134136
lastMessageUpdate.contentBlocks.length > 0
@@ -143,6 +145,7 @@ export function updateStreamingMessage(set: StoreSet, context: ClientStreamingCo
143145
if (update) {
144146
return {
145147
...msg,
148+
requestId: update.requestId ?? msg.requestId,
146149
content: '',
147150
contentBlocks:
148151
update.contentBlocks.length > 0
@@ -429,6 +432,12 @@ export const sseHandlers: Record<string, SSEHandler> = {
429432
writeActiveStreamToStorage(updatedStream)
430433
}
431434
},
435+
request_id: (data, context) => {
436+
const requestId = typeof data.data === 'string' ? data.data : undefined
437+
if (requestId) {
438+
context.requestId = requestId
439+
}
440+
},
432441
title_updated: (_data, _context, get, set) => {
433442
const title = _data.title
434443
if (!title) return

apps/sim/lib/copilot/client-sse/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface ClientContentBlock {
2222

2323
export interface StreamingContext {
2424
messageId: string
25+
requestId?: string
2526
accumulatedContent: string
2627
contentBlocks: ClientContentBlock[]
2728
currentTextBlock: ClientContentBlock | null

apps/sim/stores/panel/copilot/store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ function replaceTextBlocks(blocks: ClientContentBlock[], text: string): ClientCo
224224
function createClientStreamingContext(messageId: string): ClientStreamingContext {
225225
return {
226226
messageId,
227+
requestId: undefined,
227228
accumulatedContent: '',
228229
contentBlocks: [],
229230
currentTextBlock: null,
@@ -2043,6 +2044,7 @@ export const useCopilotStore = create<CopilotStore>()(
20432044
msg.id === assistantMessageId
20442045
? {
20452046
...msg,
2047+
requestId: context.requestId ?? msg.requestId,
20462048
content: finalContentWithOptions,
20472049
contentBlocks: sanitizedContentBlocks,
20482050
}

0 commit comments

Comments
 (0)