refactor(playground): extract message action helpers

- move message action state derivation into focused utilities.

- keep the action component focused on guarded handlers and rendering.
This commit is contained in:
QuentinHsu
2026-05-30 09:55:36 +08:00
parent 5816f69c20
commit f87af88ca5
3 changed files with 53 additions and 9 deletions
@@ -22,7 +22,10 @@ import { useCopyToClipboard } from '@/hooks/use-copy-to-clipboard'
import { TooltipProvider } from '@/components/ui/tooltip'
import { MESSAGE_ACTION_LABELS } from '../constants'
import { useMessageActionGuard } from '../hooks/use-message-action-guard'
import { getMessageContent, hasMessageContent } from '../lib'
import {
getMessageActionState,
getMessageActionsVisibilityClass,
} from '../lib'
import type { Message } from '../types'
import { MessageActionButton } from './message-action-button'
@@ -50,11 +53,8 @@ export function MessageActions({
const { copiedText, copyToClipboard } = useCopyToClipboard()
const { guardAction } = useMessageActionGuard(isGenerating)
const isAssistant = message.from === 'assistant'
const hasContent = hasMessageContent(message)
const isLoading =
message.status === 'loading' || message.status === 'streaming'
const content = getMessageContent(message)
const { content, hasContent, isAssistant, isLoading } =
getMessageActionState(message)
const isCopied = copiedText === content
const handleCopy = () => {
@@ -70,9 +70,7 @@ export function MessageActions({
const handleEdit = guardAction(() => onEdit?.(message))
const handleDelete = guardAction(() => onDelete?.(message))
const visibilityClass = alwaysVisible
? 'opacity-100'
: 'opacity-0 group-hover:opacity-100 max-md:opacity-100'
const visibilityClass = getMessageActionsVisibilityClass(alwaysVisible)
return (
<TooltipProvider delay={300}>
+1
View File
@@ -17,6 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
export * from './message-utils'
export * from './message-action-utils'
export * from './message-reasoning-utils'
export * from './message-streaming-utils'
export * from './message-update-utils'
@@ -0,0 +1,45 @@
/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { MESSAGE_ROLES, MESSAGE_STATUS } from '../constants'
import type { Message } from '../types'
import { getMessageContent, hasMessageContent } from './message-utils'
type MessageActionState = {
content: string
hasContent: boolean
isAssistant: boolean
isLoading: boolean
}
export function getMessageActionState(message: Message): MessageActionState {
return {
content: getMessageContent(message),
hasContent: hasMessageContent(message),
isAssistant: message.from === MESSAGE_ROLES.ASSISTANT,
isLoading:
message.status === MESSAGE_STATUS.LOADING ||
message.status === MESSAGE_STATUS.STREAMING,
}
}
export function getMessageActionsVisibilityClass(alwaysVisible: boolean): string {
return alwaysVisible
? 'opacity-100'
: 'opacity-0 group-hover:opacity-100 max-md:opacity-100'
}