ruvector/studio/components/ui/AIAssistantPanel/Message.Display.tsx
rUv 814f595995 feat(studio): Add complete RuVector Studio application
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>
2025-12-06 23:04:48 +00:00

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,
}