mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-05-29 19:33:34 +00:00
Major additions: - Complete Next.js studio application with 1600+ components - Docker support (Dockerfile.combined, docker-compose.yml) - GCP deployment documentation and benchmarks - SQL benchmark scripts for performance testing - Sentry integration for monitoring - Comprehensive test suite and mocks Studio features: - Dashboard and admin interfaces - Data visualization components - Authentication and user management - API integration with RuVector backend - Static data and public assets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
91 lines
2.6 KiB
TypeScript
91 lines
2.6 KiB
TypeScript
import { UIMessage as VercelMessage } from '@ai-sdk/react'
|
|
import { type PropsWithChildren } from 'react'
|
|
|
|
import { ProfileImage as ProfileImageDisplay } from 'components/ui/ProfileImage'
|
|
import { useProfileNameAndPicture } from 'lib/profile'
|
|
import { cn } from 'ui'
|
|
import { useMessageInfoContext } from './Message.Context'
|
|
import { MessageMarkdown } from './MessageMarkdown'
|
|
import { MessagePartSwitcher } from './Message.Parts'
|
|
|
|
function MessageDisplayProfileImage() {
|
|
const { username, avatarUrl } = useProfileNameAndPicture()
|
|
return (
|
|
<ProfileImageDisplay
|
|
alt={username}
|
|
src={avatarUrl}
|
|
className="w-5 h-5 shrink-0 rounded-full translate-y-0.5"
|
|
/>
|
|
)
|
|
}
|
|
|
|
function MessageDisplayContainer({
|
|
children,
|
|
onClick,
|
|
className,
|
|
}: PropsWithChildren<{ onClick?: () => void; className?: string }>) {
|
|
return (
|
|
<div
|
|
className={cn('group text-foreground-light text-sm first:mt-0', className)}
|
|
onClick={onClick}
|
|
>
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function MessageDisplayMainArea({
|
|
children,
|
|
className,
|
|
}: PropsWithChildren<{ className?: string }>) {
|
|
return <div className={cn('flex gap-4 w-auto overflow-hidden group', className)}>{children}</div>
|
|
}
|
|
|
|
function MessageDisplayContent({ message }: { message: VercelMessage }) {
|
|
const { id, isLoading, readOnly } = useMessageInfoContext()
|
|
|
|
const messageParts = message.parts
|
|
const content =
|
|
('content' in message && typeof message.content === 'string' && message.content.trim()) ||
|
|
undefined
|
|
|
|
return (
|
|
<div className="flex-1 min-w-0">
|
|
{messageParts?.length > 0
|
|
? messageParts.map((part: NonNullable<VercelMessage['parts'][number]>, idx) => {
|
|
const isLastPart = idx === messageParts.length - 1
|
|
return <MessagePartSwitcher part={part} isLastPart={isLastPart} />
|
|
})
|
|
: content && (
|
|
<MessageDisplayTextMessage id={id} isLoading={isLoading} readOnly={readOnly}>
|
|
{content}
|
|
</MessageDisplayTextMessage>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function MessageDisplayTextMessage({
|
|
id,
|
|
isLoading,
|
|
readOnly,
|
|
children,
|
|
}: PropsWithChildren<{ id: string; isLoading: boolean; readOnly?: boolean }>) {
|
|
return (
|
|
<MessageMarkdown
|
|
id={id}
|
|
isLoading={isLoading}
|
|
readOnly={readOnly}
|
|
className="prose prose-sm max-w-none break-words prose-h2:font-medium"
|
|
>
|
|
{children}
|
|
</MessageMarkdown>
|
|
)
|
|
}
|
|
|
|
export const MessageDisplay = {
|
|
Container: MessageDisplayContainer,
|
|
Content: MessageDisplayContent,
|
|
MainArea: MessageDisplayMainArea,
|
|
ProfileImage: MessageDisplayProfileImage,
|
|
}
|