mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-08 07:17:39 +00:00
refine message actions and metadata
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import { useState } from 'react'
|
||||
import { MessagePrimitive, useAssistantState } from '@assistant-ui/react'
|
||||
import { useHappyChatContext } from '@/components/AssistantChat/context'
|
||||
import type { HappyChatMessageMetadata } from '@/lib/assistant-runtime'
|
||||
@@ -6,16 +5,11 @@ import { MessageStatusIndicator } from '@/components/AssistantChat/messages/Mess
|
||||
import { MessageAttachments } from '@/components/AssistantChat/messages/MessageAttachments'
|
||||
import { UserBubbleContent, getUserBubbleClassName, shouldShowMessageStatus } from '@/components/AssistantChat/messages/user-bubble'
|
||||
import { CliOutputBlock } from '@/components/CliOutputBlock'
|
||||
import { CopyIcon, CheckIcon } from '@/components/icons'
|
||||
import { useCopyToClipboard } from '@/hooks/useCopyToClipboard'
|
||||
import { getConversationMessageAnchorId } from '@/chat/outline'
|
||||
import { MessageMetadata } from '@/components/AssistantChat/messages/MessageMetadata'
|
||||
import { MessageTimestamp } from '@/components/AssistantChat/messages/MessageTimestamp'
|
||||
import { MessageActions } from '@/components/AssistantChat/messages/MessageActions'
|
||||
|
||||
export function HappyUserMessage() {
|
||||
const ctx = useHappyChatContext()
|
||||
const { copied, copy } = useCopyToClipboard()
|
||||
const [showMetadata, setShowMetadata] = useState(false)
|
||||
const role = useAssistantState(({ message }) => message.role)
|
||||
const messageId = useAssistantState(({ message }) => message.id)
|
||||
const text = useAssistantState(({ message }) => {
|
||||
@@ -46,10 +40,6 @@ export function HappyUserMessage() {
|
||||
if (custom?.kind !== 'cli-output') return ''
|
||||
return message.content.find((part) => part.type === 'text')?.text ?? ''
|
||||
})
|
||||
const invokedAt = useAssistantState(({ message }) => (message.metadata.custom as Partial<HappyChatMessageMetadata> | undefined)?.invokedAt)
|
||||
|
||||
const hasMetadata = invokedAt != null
|
||||
|
||||
if (role !== 'user') return null
|
||||
const canRetry = status === 'failed' && typeof localId === 'string' && Boolean(ctx.onRetryMessage)
|
||||
const onRetry = canRetry ? () => ctx.onRetryMessage!(localId) : undefined
|
||||
@@ -59,26 +49,11 @@ export function HappyUserMessage() {
|
||||
return (
|
||||
<MessagePrimitive.Root
|
||||
id={getConversationMessageAnchorId(messageId)}
|
||||
className="scroll-mt-4 px-1 min-w-0 max-w-full overflow-x-hidden"
|
||||
className="happy-message scroll-mt-4 px-1 min-w-0 max-w-full overflow-x-hidden"
|
||||
>
|
||||
<div className="ml-auto w-full max-w-[92%]">
|
||||
<CliOutputBlock text={cliText} />
|
||||
<div className="mt-1 flex items-center justify-end gap-2">
|
||||
<MessageTimestamp className="text-[10px] leading-none text-[var(--app-hint)]" />
|
||||
{hasMetadata && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowMetadata((open) => !open)}
|
||||
aria-expanded={showMetadata}
|
||||
className="text-[10px] text-[var(--app-hint)] underline-offset-2 hover:text-[var(--app-fg)] hover:underline"
|
||||
>
|
||||
{showMetadata ? 'Hide info' : 'Show info'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{showMetadata && invokedAt != null && (
|
||||
<MessageMetadata invokedAt={invokedAt} />
|
||||
)}
|
||||
<MessageActions align="end" copyText={cliText} />
|
||||
</div>
|
||||
</MessagePrimitive.Root>
|
||||
)
|
||||
@@ -90,49 +65,22 @@ export function HappyUserMessage() {
|
||||
return (
|
||||
<MessagePrimitive.Root
|
||||
id={getConversationMessageAnchorId(messageId)}
|
||||
className={`${getUserBubbleClassName(status)} group/msg scroll-mt-4`}
|
||||
className="happy-message flex flex-col items-end scroll-mt-4"
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className={getUserBubbleClassName(status)}>
|
||||
<div className="flex items-start gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
{hasText ? <UserBubbleContent text={text} /> : null}
|
||||
{hasAttachments ? <MessageAttachments attachments={attachments} /> : null}
|
||||
</div>
|
||||
{(hasText || showStatus) && (
|
||||
{showStatus && (
|
||||
<div className="happy-message-actions-first-line flex shrink-0 items-center gap-1">
|
||||
{hasText && (
|
||||
<button
|
||||
type="button"
|
||||
title="Copy"
|
||||
className="rounded-md p-0.5 opacity-60 transition-[opacity,background-color] hover:bg-[var(--app-chat-user-chip-bg)] sm:opacity-0 sm:group-hover/msg:opacity-100"
|
||||
onClick={() => copy(text)}
|
||||
>
|
||||
{copied
|
||||
? <CheckIcon className="h-3.5 w-3.5 text-green-500" />
|
||||
: <CopyIcon className="h-3.5 w-3.5 text-[var(--app-hint)]" />}
|
||||
</button>
|
||||
)}
|
||||
{showStatus ? <MessageStatusIndicator status={status} onRetry={onRetry} /> : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-end items-center gap-2">
|
||||
<MessageTimestamp className="text-[10px] leading-none text-[var(--app-hint)]" />
|
||||
{hasMetadata && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowMetadata((open) => !open)}
|
||||
aria-expanded={showMetadata}
|
||||
className="text-[10px] text-[var(--app-hint)] underline-offset-2 hover:text-[var(--app-fg)] hover:underline"
|
||||
>
|
||||
{showMetadata ? 'Hide info' : 'Show info'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{showMetadata && invokedAt != null && (
|
||||
<MessageMetadata invokedAt={invokedAt} />
|
||||
)}
|
||||
</div>
|
||||
<MessageActions align="end" copyText={hasText ? text : undefined} />
|
||||
</MessagePrimitive.Root>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user